diff options
author | Rene Stoeckel <[email protected]> | 2004-08-20 21:29:58 +0000 |
---|---|---|
committer | Rene Stoeckel <[email protected]> | 2004-08-20 21:29:58 +0000 |
commit | 93a1cb6d6bfa9d7a80c004100125c829f1f36e86 (patch) | |
tree | 4ca88afc7718f8e63bd7f91aeccfe3c0fe66634e /src/jake2/server/SV.java | |
parent | a1a1c7334c9b03113344078d2d7977193a1d7b5e (diff) |
savegames now seem to work.
Diffstat (limited to 'src/jake2/server/SV.java')
-rw-r--r-- | src/jake2/server/SV.java | 913 |
1 files changed, 507 insertions, 406 deletions
diff --git a/src/jake2/server/SV.java b/src/jake2/server/SV.java index 4792264..540e3ea 100644 --- a/src/jake2/server/SV.java +++ b/src/jake2/server/SV.java @@ -2,9 +2,9 @@ * SV.java * Copyright (C) 2003 * - * $Id: SV.java,v 1.5 2004-07-30 06:07:23 hzi Exp $ + * $Id: SV.java,v 1.6 2004-08-20 21:29:57 salomo Exp $ */ - /* +/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or @@ -35,198 +35,219 @@ import jake2.util.Math3D; /** * SV */ -public final class SV { +public final class SV +{ //file_io //===================================================================== //g_phys - + /////////////////////////////////////// - public static edict_t[] SV_TestEntityPosition(edict_t ent) { + public static edict_t[] SV_TestEntityPosition(edict_t ent) + { trace_t trace; int mask; - + if (ent.clipmask != 0) - mask = ent.clipmask; + mask= ent.clipmask; else - mask = Defines.MASK_SOLID; - - trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, ent.s.origin, ent, mask); - + mask= Defines.MASK_SOLID; + + trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, ent.s.origin, ent, mask); + if (trace.startsolid) return GameBase.g_edicts; - + return null; } /////////////////////////////////////// - public static void SV_CheckVelocity(edict_t ent) { + public static void SV_CheckVelocity(edict_t ent) + { int i; - + // // bound velocity // - for (i = 0; i < 3; i++) { + for (i= 0; i < 3; i++) + { if (ent.velocity[i] > GameBase.sv_maxvelocity.value) - ent.velocity[i] = GameBase.sv_maxvelocity.value; + ent.velocity[i]= GameBase.sv_maxvelocity.value; else if (ent.velocity[i] < -GameBase.sv_maxvelocity.value) - ent.velocity[i] = -GameBase.sv_maxvelocity.value; + ent.velocity[i]= -GameBase.sv_maxvelocity.value; } } /** * Runs thinking code for this frame if necessary. */ - public static boolean SV_RunThink(edict_t ent) { + public static boolean SV_RunThink(edict_t ent) + { float thinktime; - - thinktime = ent.nextthink; + + thinktime= ent.nextthink; if (thinktime <= 0) return true; if (thinktime > GameBase.level.time + 0.001) return true; - - ent.nextthink = 0; - + + ent.nextthink= 0; + if (ent.think == null) Com.Error(Defines.ERR_FATAL, "NULL ent.think"); ent.think.think(ent); - + return false; } /** * Two entities have touched, so run their touch functions. */ - public static void SV_Impact(edict_t e1, trace_t trace) { + public static void SV_Impact(edict_t e1, trace_t trace) + { edict_t e2; // cplane_t backplane; - - e2 = trace.ent; - + + e2= trace.ent; + if (e1.touch != null && e1.solid != Defines.SOLID_NOT) e1.touch.touch(e1, e2, trace.plane, trace.surface); - + if (e2.touch != null && e2.solid != Defines.SOLID_NOT) e2.touch.touch(e2, e1, null, null); } - public static int SV_FlyMove(edict_t ent, float time, int mask) { + public static int SV_FlyMove(edict_t ent, float time, int mask) + { edict_t hit; int bumpcount, numbumps; - float[] dir = { 0.0f, 0.0f, 0.0f }; + float[] dir= { 0.0f, 0.0f, 0.0f }; float d; int numplanes; - float[][] planes = new float[GameBase.MAX_CLIP_PLANES][3]; - float[] primal_velocity = { 0.0f, 0.0f, 0.0f }; - float[] original_velocity = { 0.0f, 0.0f, 0.0f }; - float[] new_velocity = { 0.0f, 0.0f, 0.0f }; + float[][] planes= new float[GameBase.MAX_CLIP_PLANES][3]; + float[] primal_velocity= { 0.0f, 0.0f, 0.0f }; + float[] original_velocity= { 0.0f, 0.0f, 0.0f }; + float[] new_velocity= { 0.0f, 0.0f, 0.0f }; int i, j; trace_t trace; - float[] end = { 0.0f, 0.0f, 0.0f }; + float[] end= { 0.0f, 0.0f, 0.0f }; float time_left; int blocked; - - numbumps = 4; - - blocked = 0; + + numbumps= 4; + + blocked= 0; Math3D.VectorCopy(ent.velocity, original_velocity); Math3D.VectorCopy(ent.velocity, primal_velocity); - numplanes = 0; - - time_left = time; - - ent.groundentity = null; - for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { - for (i = 0; i < 3; i++) - end[i] = ent.s.origin[i] + time_left * ent.velocity[i]; - - trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, mask); - - if (trace.allsolid) { // entity is trapped in another solid + numplanes= 0; + + time_left= time; + + ent.groundentity= null; + for (bumpcount= 0; bumpcount < numbumps; bumpcount++) + { + for (i= 0; i < 3; i++) + end[i]= ent.s.origin[i] + time_left * ent.velocity[i]; + + trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, mask); + + if (trace.allsolid) + { // entity is trapped in another solid Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); return 3; } - - if (trace.fraction > 0) { // actually covered some distance + + if (trace.fraction > 0) + { // actually covered some distance Math3D.VectorCopy(trace.endpos, ent.s.origin); Math3D.VectorCopy(ent.velocity, original_velocity); - numplanes = 0; + numplanes= 0; } - + if (trace.fraction == 1) break; // moved the entire distance - - hit = trace.ent; - - if (trace.plane.normal[2] > 0.7) { + + hit= trace.ent; + + if (trace.plane.normal[2] > 0.7) + { blocked |= 1; // floor - if (hit.solid == Defines.SOLID_BSP) { - ent.groundentity = hit; - ent.groundentity_linkcount = hit.linkcount; + if (hit.solid == Defines.SOLID_BSP) + { + ent.groundentity= hit; + ent.groundentity_linkcount= hit.linkcount; } } - if (trace.plane.normal[2] == 0.0f) { + if (trace.plane.normal[2] == 0.0f) + { blocked |= 2; // step } - + // // run the impact function // SV_Impact(ent, trace); if (!ent.inuse) break; // removed by the impact function - + time_left -= time_left * trace.fraction; - + // cliped to another plane - if (numplanes >= GameBase.MAX_CLIP_PLANES) { // this shouldn't really happen + if (numplanes >= GameBase.MAX_CLIP_PLANES) + { // this shouldn't really happen Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); return 3; } - + Math3D.VectorCopy(trace.plane.normal, planes[numplanes]); numplanes++; - + // // modify original_velocity so it parallels all of the clip planes // - for (i = 0; i < numplanes; i++) { + for (i= 0; i < numplanes; i++) + { GameBase.ClipVelocity(original_velocity, planes[i], new_velocity, 1); - - for (j = 0; j < numplanes; j++) - if ((j != i) && Math3D.VectorCompare(planes[i], planes[j]) == 0.0f) { + + for (j= 0; j < numplanes; j++) + if ((j != i) && Math3D.VectorCompare(planes[i], planes[j]) == 0.0f) + { if (Math3D.DotProduct(new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } - - if (i != numplanes) { // go along this plane + + if (i != numplanes) + { // go along this plane Math3D.VectorCopy(new_velocity, ent.velocity); - } else { // go along the crease - if (numplanes != 2) { + } + else + { // go along the crease + if (numplanes != 2) + { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); return 7; } Math3D.CrossProduct(planes[0], planes[1], dir); - d = Math3D.DotProduct(dir, ent.velocity); + d= Math3D.DotProduct(dir, ent.velocity); Math3D.VectorScale(dir, d, ent.velocity); } - + // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // - if (Math3D.DotProduct(ent.velocity, primal_velocity) <= 0) { + if (Math3D.DotProduct(ent.velocity, primal_velocity) <= 0) + { Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); return blocked; } } - + return blocked; } @@ -236,55 +257,61 @@ public final class SV { ============ */ - public static void SV_AddGravity(edict_t ent) { + public static void SV_AddGravity(edict_t ent) + { ent.velocity[2] -= ent.gravity * GameBase.sv_gravity.value * Defines.FRAMETIME; } /** * Does not change the entities velocity at all */ - public static trace_t SV_PushEntity(edict_t ent, float[] push) { + public static trace_t SV_PushEntity(edict_t ent, float[] push) + { trace_t trace; - float[] start = { 0, 0, 0 }; - float[] end = { 0, 0, 0 }; + float[] start= { 0, 0, 0 }; + float[] end= { 0, 0, 0 }; int mask; - + Math3D.VectorCopy(ent.s.origin, start); Math3D.VectorAdd(start, push, end); - + // FIXME: test this // a goto statement was replaced. - boolean retry; - - do { + boolean retry= false; + + do + { if (ent.clipmask != 0) - mask = ent.clipmask; + mask= ent.clipmask; else - mask = Defines.MASK_SOLID; - - trace = GameBase.gi.trace(start, ent.mins, ent.maxs, end, ent, mask); - + mask= Defines.MASK_SOLID; + + trace= GameBase.gi.trace(start, ent.mins, ent.maxs, end, ent, mask); + Math3D.VectorCopy(trace.endpos, ent.s.origin); GameBase.gi.linkentity(ent); - - retry = false; - if (trace.fraction != 1.0) { + + retry= false; + if (trace.fraction != 1.0) + { SV_Impact(ent, trace); - + // if the pushed entity went away and the pusher is still there - if (!trace.ent.inuse && ent.inuse) { + if (!trace.ent.inuse && ent.inuse) + { // move the pusher back and try again Math3D.VectorCopy(start, ent.s.origin); GameBase.gi.linkentity(ent); //goto retry; - retry = true; + retry= true; } } - } while (retry); - + } + while (retry); + if (ent.inuse) GameBase.G_TouchTriggers(ent); - + return trace; } @@ -296,61 +323,65 @@ public final class SV { otherwise riders would continue to slide. ============ */ - public static boolean SV_Push(edict_t pusher, float[] move, float[] amove) { + public static boolean SV_Push(edict_t pusher, float[] move, float[] amove) + { int i, e; edict_t check, block[]; - float[] mins = { 0, 0, 0 }; - float[] maxs = { 0, 0, 0 }; + float[] mins= { 0, 0, 0 }; + float[] maxs= { 0, 0, 0 }; pushed_t p; - float[] org = { 0, 0, 0 }; - float[] org2 = { 0, 0, 0 }; - float[] move2 = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }; - float[] right = { 0, 0, 0 }; - float[] up = { 0, 0, 0 }; - + float[] org= { 0, 0, 0 }; + float[] org2= { 0, 0, 0 }; + float[] move2= { 0, 0, 0 }; + float[] forward= { 0, 0, 0 }; + float[] right= { 0, 0, 0 }; + float[] up= { 0, 0, 0 }; + // clamp the move to 1/8 units, so the position will // be accurate for client side prediction - for (i = 0; i < 3; i++) { + for (i= 0; i < 3; i++) + { float temp; - temp = move[i] * 8.0f; + temp= move[i] * 8.0f; if (temp > 0.0) temp += 0.5; else temp -= 0.5; - move[i] = 0.125f * (int) temp; + move[i]= 0.125f * (int) temp; } - + // find the bounding box - for (i = 0; i < 3; i++) { - mins[i] = pusher.absmin[i] + move[i]; - maxs[i] = pusher.absmax[i] + move[i]; + for (i= 0; i < 3; i++) + { + mins[i]= pusher.absmin[i] + move[i]; + maxs[i]= pusher.absmax[i] + move[i]; } - + // we need this for pushing things later Math3D.VectorSubtract(GameBase.vec3_origin, amove, org); Math3D.AngleVectors(org, forward, right, up); - + // save the pusher's original position - GameBase.pushed[GameBase.pushed_p].ent = pusher; + GameBase.pushed[GameBase.pushed_p].ent= pusher; Math3D.VectorCopy(pusher.s.origin, GameBase.pushed[GameBase.pushed_p].origin); Math3D.VectorCopy(pusher.s.angles, GameBase.pushed[GameBase.pushed_p].angles); - + if (pusher.client != null) - GameBase.pushed[GameBase.pushed_p].deltayaw = pusher.client.ps.pmove.delta_angles[Defines.YAW]; - + GameBase.pushed[GameBase.pushed_p].deltayaw= pusher.client.ps.pmove.delta_angles[Defines.YAW]; + GameBase.pushed_p++; - + // move the pusher to it's final position Math3D.VectorAdd(pusher.s.origin, move, pusher.s.origin); Math3D.VectorAdd(pusher.s.angles, amove, pusher.s.angles); GameBase.gi.linkentity(pusher); - + // see if any solid entities are inside the final position - + //check= g_edicts + 1; - for (e = 1; e < GameBase.globals.num_edicts; e++) { - check = GameBase.g_edicts[e]; + for (e= 1; e < GameBase.globals.num_edicts; e++) + { + check= GameBase.g_edicts[e]; if (!check.inuse) continue; if (check.movetype == Defines.MOVETYPE_PUSH @@ -358,12 +389,13 @@ public final class SV { || check.movetype == Defines.MOVETYPE_NONE || check.movetype == Defines.MOVETYPE_NOCLIP) continue; - + if (check.area.prev == null) continue; // not linked in anywhere - + // if the entity is standing on the pusher, it will definitely be moved - if (check.groundentity != pusher) { + if (check.groundentity != pusher) + { // see if the ent needs to be tested if (check.absmin[0] >= maxs[0] || check.absmin[1] >= maxs[1] @@ -372,79 +404,85 @@ public final class SV { || check.absmax[1] <= mins[1] || check.absmax[2] <= mins[2]) continue; - + // see if the ent's bbox is inside the pusher's final position if (SV_TestEntityPosition(check) == null) continue; } - - if ((pusher.movetype == Defines.MOVETYPE_PUSH) || (check.groundentity == pusher)) { + + if ((pusher.movetype == Defines.MOVETYPE_PUSH) || (check.groundentity == pusher)) + { // move this entity - GameBase.pushed[GameBase.pushed_p].ent = check; + GameBase.pushed[GameBase.pushed_p].ent= check; Math3D.VectorCopy(check.s.origin, GameBase.pushed[GameBase.pushed_p].origin); Math3D.VectorCopy(check.s.angles, GameBase.pushed[GameBase.pushed_p].angles); GameBase.pushed_p++; - + // try moving the contacted entity Math3D.VectorAdd(check.s.origin, move, check.s.origin); - if (check.client != null) { // FIXME: doesn't rotate monsters? + if (check.client != null) + { // FIXME: doesn't rotate monsters? check.client.ps.pmove.delta_angles[Defines.YAW] += amove[Defines.YAW]; } - + // figure movement due to the pusher's amove Math3D.VectorSubtract(check.s.origin, pusher.s.origin, org); - org2[0] = Math3D.DotProduct(org, forward); - org2[1] = -Math3D.DotProduct(org, right); - org2[2] = Math3D.DotProduct(org, up); + org2[0]= Math3D.DotProduct(org, forward); + org2[1]= -Math3D.DotProduct(org, right); + org2[2]= Math3D.DotProduct(org, up); Math3D.VectorSubtract(org2, org, move2); Math3D.VectorAdd(check.s.origin, move2, check.s.origin); - + // may have pushed them off an edge if (check.groundentity != pusher) - check.groundentity = null; - - block = SV_TestEntityPosition(check); - if (block == null) { // pushed ok + check.groundentity= null; + + block= SV_TestEntityPosition(check); + if (block == null) + { // pushed ok GameBase.gi.linkentity(check); // impact? continue; } - + // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed // FIXME: this doesn't acount for rotation Math3D.VectorSubtract(check.s.origin, move, check.s.origin); - block = SV_TestEntityPosition(check); - - if (block == null) { + block= SV_TestEntityPosition(check); + + if (block == null) + { GameBase.pushed_p--; continue; } } - + // save off the obstacle so we can call the block function - GameBase.obstacle = check; - + GameBase.obstacle= check; + // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position - for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--) { - p = GameBase.pushed[ip]; + for (int ip= GameBase.pushed_p - 1; ip >= 0; ip--) + { + p= GameBase.pushed[ip]; Math3D.VectorCopy(p.origin, p.ent.s.origin); Math3D.VectorCopy(p.angles, p.ent.s.angles); - if (p.ent.client != null) { - p.ent.client.ps.pmove.delta_angles[Defines.YAW] = (short) p.deltayaw; + if (p.ent.client != null) + { + p.ent.client.ps.pmove.delta_angles[Defines.YAW]= (short) p.deltayaw; } GameBase.gi.linkentity(p.ent); } return false; } - + // FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger - for (int ip = GameBase.pushed_p - 1; ip >= 0; ip--) + for (int ip= GameBase.pushed_p - 1; ip >= 0; ip--) GameBase.G_TouchTriggers(GameBase.pushed[ip].ent); - + return true; } @@ -456,57 +494,65 @@ public final class SV { push all box objects ================ */ - public static void SV_Physics_Pusher(edict_t ent) { - float[] move = { 0, 0, 0 }; - float[] amove = { 0, 0, 0 }; + public static void SV_Physics_Pusher(edict_t ent) + { + float[] move= { 0, 0, 0 }; + float[] amove= { 0, 0, 0 }; edict_t part, mv; - + // if not a team captain, so movement will be handled elsewhere if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) return; - + // make sure all team slaves can move before commiting // any moves or calling any think functions // if the move is blocked, all moved objects will be backed out // retry: - GameBase.pushed_p = 0; - for (part = ent; part != null; part = part.teamchain) { + GameBase.pushed_p= 0; + for (part= ent; part != null; part= part.teamchain) + { if (part.velocity[0] != 0 || part.velocity[1] != 0 || part.velocity[2] != 0 || part.avelocity[0] != 0 || part.avelocity[1] != 0 - || part.avelocity[2] != 0) { // object is moving + || part.avelocity[2] != 0) + { // object is moving Math3D.VectorScale(part.velocity, Defines.FRAMETIME, move); Math3D.VectorScale(part.avelocity, Defines.FRAMETIME, amove); - + if (!SV_Push(part, move, amove)) break; // move was blocked } } if (GameBase.pushed_p > Defines.MAX_EDICTS) + SV_GAME.PF_error(Defines.ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted"); if (part != null) { // the move failed, bump all nextthink times and back out moves - for (mv = ent; mv != null; mv = mv.teamchain) { + for (mv= ent; mv != null; mv= mv.teamchain) + { if (mv.nextthink > 0) mv.nextthink += Defines.FRAMETIME; } - + // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (part.blocked != null) part.blocked.blocked(part, GameBase.obstacle); - } else { // the move succeeded, so call all think functions - for (part = ent; part != null; part = part.teamchain) { + } + else + { // the move succeeded, so call all think functions + for (part= ent; part != null; part= part.teamchain) + { SV_RunThink(part); } } } // ================================================================== - + /* ============= SV_Physics_None @@ -514,7 +560,8 @@ public final class SV { Non moving objects can only think ============= */ - public static void SV_Physics_None(edict_t ent) { + public static void SV_Physics_None(edict_t ent) + { // regular thinking SV_RunThink(ent); } @@ -526,14 +573,15 @@ public final class SV { A moving object that doesn't obey physics ============= */ - public static void SV_Physics_Noclip(edict_t ent) { + public static void SV_Physics_Noclip(edict_t ent) + { // regular thinking if (!SV_RunThink(ent)) return; - + Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); Math3D.VectorMA(ent.s.origin, Defines.FRAMETIME, ent.velocity, ent.s.origin); - + GameBase.gi.linkentity(ent); } @@ -544,7 +592,7 @@ public final class SV { ============================================================================== */ - + /* ============= SV_Physics_Toss @@ -552,90 +600,96 @@ public final class SV { Toss, bounce, and fly movement. When onground, do nothing. ============= */ - public static void SV_Physics_Toss(edict_t ent) { + public static void SV_Physics_Toss(edict_t ent) + { + trace_t trace; - float[] move = { 0, 0, 0 }; + float[] move= { 0, 0, 0 }; float backoff; edict_t slave; boolean wasinwater; boolean isinwater; - float[] old_origin = { 0, 0, 0 }; - + float[] old_origin= { 0, 0, 0 }; + // regular thinking SV_RunThink(ent); - + // if not a team captain, so movement will be handled elsewhere if ((ent.flags & Defines.FL_TEAMSLAVE) != 0) return; - + if (ent.velocity[2] > 0) - ent.groundentity = null; - - // check for the groundentity going away + ent.groundentity= null; + + // check for the groundentity going away if (ent.groundentity != null) if (!ent.groundentity.inuse) - ent.groundentity = null; - + ent.groundentity= null; + // if onground, return without moving if (ent.groundentity != null) return; - + Math3D.VectorCopy(ent.s.origin, old_origin); - + SV_CheckVelocity(ent); - + // add gravity if (ent.movetype != Defines.MOVETYPE_FLY && ent.movetype != Defines.MOVETYPE_FLYMISSILE) SV_AddGravity(ent); - + // move angles Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); - + // move origin Math3D.VectorScale(ent.velocity, Defines.FRAMETIME, move); - trace = SV_PushEntity(ent, move); + trace= SV_PushEntity(ent, move); if (!ent.inuse) return; - - if (trace.fraction < 1) { + + if (trace.fraction < 1) + { if (ent.movetype == Defines.MOVETYPE_BOUNCE) - backoff = 1.5f; + backoff= 1.5f; else - backoff = 1; - + backoff= 1; + GameBase.ClipVelocity(ent.velocity, trace.plane.normal, ent.velocity, backoff); - + // stop if on ground - if (trace.plane.normal[2] > 0.7) { - if (ent.velocity[2] < 60 || ent.movetype != Defines.MOVETYPE_BOUNCE) { - ent.groundentity = trace.ent; - ent.groundentity_linkcount = trace.ent.linkcount; + if (trace.plane.normal[2] > 0.7) + { + if (ent.velocity[2] < 60 || ent.movetype != Defines.MOVETYPE_BOUNCE) + { + ent.groundentity= trace.ent; + ent.groundentity_linkcount= trace.ent.linkcount; Math3D.VectorCopy(GameBase.vec3_origin, ent.velocity); Math3D.VectorCopy(GameBase.vec3_origin, ent.avelocity); } } - + // if (ent.touch) // ent.touch (ent, trace.ent, &trace.plane, trace.surface); } - + // check for water transition - wasinwater = (ent.watertype & Defines.MASK_WATER) != 0; - ent.watertype = GameBase.gi.pointcontents.pointcontents(ent.s.origin); - isinwater = (ent.watertype & Defines.MASK_WATER) != 0; - + wasinwater= (ent.watertype & Defines.MASK_WATER) != 0; + ent.watertype= GameBase.gi.pointcontents.pointcontents(ent.s.origin); + isinwater= (ent.watertype & Defines.MASK_WATER) != 0; + if (isinwater) - ent.waterlevel = 1; + ent.waterlevel= 1; else - ent.waterlevel = 0; - + ent.waterlevel= 0; + if (!wasinwater && isinwater) GameBase.gi.positioned_sound(old_origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) GameBase.gi.positioned_sound(ent.s.origin, ent, Defines.CHAN_AUTO, GameBase.gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); - + // move teamslaves - for (slave = ent.teamchain; slave != null; slave = slave.teamchain) { + for (slave= ent.teamchain; slave != null; slave= slave.teamchain) + { Math3D.VectorCopy(ent.s.origin, slave.s.origin); GameBase.gi.linkentity(slave); } @@ -648,7 +702,7 @@ public final class SV { =============================================================================== */ - + /* ============= SV_Physics_Step @@ -661,128 +715,140 @@ public final class SV { FIXME: is this true? ============= */ - + // FIXME: hacked in for E3 demo - - public static void SV_AddRotationalFriction(edict_t ent) { + + public static void SV_AddRotationalFriction(edict_t ent) + { int n; float adjustment; - + Math3D.VectorMA(ent.s.angles, Defines.FRAMETIME, ent.avelocity, ent.s.angles); - adjustment = Defines.FRAMETIME * Defines.sv_stopspeed * Defines.sv_friction; - for (n = 0; n < 3; n++) { - if (ent.avelocity[n] > 0) { + adjustment= Defines.FRAMETIME * Defines.sv_stopspeed * Defines.sv_friction; + for (n= 0; n < 3; n++) + { + if (ent.avelocity[n] > 0) + { ent.avelocity[n] -= adjustment; if (ent.avelocity[n] < 0) - ent.avelocity[n] = 0; - } else { + ent.avelocity[n]= 0; + } + else + { ent.avelocity[n] += adjustment; if (ent.avelocity[n] > 0) - ent.avelocity[n] = 0; + ent.avelocity[n]= 0; } } } - public static void SV_Physics_Step(edict_t ent) { + public static void SV_Physics_Step(edict_t ent) + { boolean wasonground; - boolean hitsound = false; + boolean hitsound= false; float vel[]; float speed, newspeed, control; float friction; edict_t groundentity; int mask; - + // airborn monsters should always check for ground if (ent.groundentity == null) M.M_CheckGround(ent); - - groundentity = ent.groundentity; - + + groundentity= ent.groundentity; + SV_CheckVelocity(ent); - + if (groundentity != null) - wasonground = true; + wasonground= true; else - wasonground = false; - + wasonground= false; + if (ent.avelocity[0] != 0 || ent.avelocity[1] != 0 || ent.avelocity[2] != 0) SV_AddRotationalFriction(ent); - + // add gravity except: // flying monsters // swimming monsters who are in the water if (!wasonground) if (0 == (ent.flags & Defines.FL_FLY)) - if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel > 2))) { + if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel > 2))) + { if (ent.velocity[2] < GameBase.sv_gravity.value * -0.1) - hitsound = true; + hitsound= true; if (ent.waterlevel == 0) SV_AddGravity(ent); } - + // friction for flying monsters that have been given vertical velocity - if ((ent.flags & Defines.FL_FLY) != 0 && (ent.velocity[2] != 0)) { - speed = Math.abs(ent.velocity[2]); - control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - friction = Defines.sv_friction / 3; - newspeed = speed - (Defines.FRAMETIME * control * friction); + if ((ent.flags & Defines.FL_FLY) != 0 && (ent.velocity[2] != 0)) + { + speed= Math.abs(ent.velocity[2]); + control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; + friction= Defines.sv_friction / 3; + newspeed= speed - (Defines.FRAMETIME * control * friction); if (newspeed < 0) - newspeed = 0; + newspeed= 0; newspeed /= speed; ent.velocity[2] *= newspeed; } - + // friction for flying monsters that have been given vertical velocity - if ((ent.flags & Defines.FL_SWIM) != 0 && (ent.velocity[2] != 0)) { - speed = Math.abs(ent.velocity[2]); - control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - newspeed = speed - (Defines.FRAMETIME * control * Defines.sv_waterfriction * ent.waterlevel); + if ((ent.flags & Defines.FL_SWIM) != 0 && (ent.velocity[2] != 0)) + { + speed= Math.abs(ent.velocity[2]); + control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; + newspeed= speed - (Defines.FRAMETIME * control * Defines.sv_waterfriction * ent.waterlevel); if (newspeed < 0) - newspeed = 0; + newspeed= 0; newspeed /= speed; ent.velocity[2] *= newspeed; } - - if (ent.velocity[2] != 0 || ent.velocity[1] != 0 || ent.velocity[0] != 0) { + + if (ent.velocity[2] != 0 || ent.velocity[1] != 0 || ent.velocity[0] != 0) + { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || 0 != (ent.flags & (Defines.FL_SWIM | Defines.FL_FLY))) - if (!(ent.health <= 0.0 && !M.M_CheckBottom(ent))) { - vel = ent.velocity; - speed = (float) Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]); - if (speed != 0) { - friction = Defines.sv_friction; - - control = speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; - newspeed = speed - Defines.FRAMETIME * control * friction; - + if (!(ent.health <= 0.0 && !M.M_CheckBottom(ent))) + { + vel= ent.velocity; + speed= (float) Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]); + if (speed != 0) + { + friction= Defines.sv_friction; + + control= speed < Defines.sv_stopspeed ? Defines.sv_stopspeed : speed; + newspeed= speed - Defines.FRAMETIME * control * friction; + if (newspeed < 0) - newspeed = 0; + newspeed= 0; newspeed /= speed; - + vel[0] *= newspeed; vel[1] *= newspeed; } } - + if ((ent.svflags & Defines.SVF_MONSTER) != 0) - mask = Defines.MASK_MONSTERSOLID; + mask= Defines.MASK_MONSTERSOLID; else - mask = Defines.MASK_SOLID; - + mask= Defines.MASK_SOLID; + SV_FlyMove(ent, Defines.FRAMETIME, mask); - + GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); if (!ent.inuse) return; - + if (ent.groundentity != null) if (!wasonground) if (hitsound) GameBase.gi.sound(ent, 0, GameBase.gi.soundindex("world/land.wav"), 1, 1, 0); } - + // regular thinking SV_RunThink(ent); } @@ -799,38 +865,45 @@ public final class SV { */ // FIXME since we need to test end position contents here, can we avoid doing // it again later in catagorize position? - public static boolean SV_movestep(edict_t ent, float[] move, boolean relink) { + public static boolean SV_movestep(edict_t ent, float[] move, boolean relink) + { float dz; - float[] oldorg = { 0, 0, 0 }; - float[] neworg = { 0, 0, 0 }; - float[] end = { 0, 0, 0 }; - - trace_t trace = null;// = new trace_t(); + float[] oldorg= { 0, 0, 0 }; + float[] neworg= { 0, 0, 0 }; + float[] end= { 0, 0, 0 }; + + trace_t trace= null; // = new trace_t(); int i; float stepsize; - float[] test = { 0, 0, 0 }; + float[] test= { 0, 0, 0 }; int contents; - + // try the move Math3D.VectorCopy(ent.s.origin, oldorg); Math3D.VectorAdd(ent.s.origin, move, neworg); - + // flying monsters don't step up - if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) { + if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0) + { // try one move with vertical motion, then one without - for (i = 0; i < 2; i++) { + for (i= 0; i < 2; i++) + { Math3D.VectorAdd(ent.s.origin, move, neworg); - if (i == 0 && ent.enemy != null) { + if (i == 0 && ent.enemy != null) + { if (ent.goalentity == null) - ent.goalentity = ent.enemy; - dz = ent.s.origin[2] - ent.goalentity.s.origin[2]; - if (ent.goalentity.client != null) { + ent.goalentity= ent.enemy; + dz= ent.s.origin[2] - ent.goalentity.s.origin[2]; + if (ent.goalentity.client != null) + { if (dz > 40) neworg[2] -= 8; if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel < 2))) if (dz < 30) neworg[2] += 8; - } else { + } + else + { if (dz > 8) neworg[2] -= 8; else if (dz > 0) @@ -841,104 +914,118 @@ public final class SV { neworg[2] += dz; } } - trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, neworg, ent, Defines.MASK_MONSTERSOLID); - + trace= GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, neworg, ent, Defines.MASK_MONSTERSOLID); + // fly monsters don't enter water voluntarily - if ((ent.flags & Defines.FL_FLY) != 0) { - if (ent.waterlevel == 0) { - test[0] = trace.endpos[0]; - test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent.mins[2] + 1; - contents = GameBase.gi.pointcontents.pointcontents(test); + if ((ent.flags & Defines.FL_FLY) != 0) + { + if (ent.waterlevel == 0) + { + test[0]= trace.endpos[0]; + test[1]= trace.endpos[1]; + test[2]= trace.endpos[2] + ent.mins[2] + 1; + contents= GameBase.gi.pointcontents.pointcontents(test); if ((contents & Defines.MASK_WATER) != 0) return false; } } - + // swim monsters don't exit water voluntarily - if ((ent.flags & Defines.FL_SWIM) != 0) { - if (ent.waterlevel < 2) { - test[0] = trace.endpos[0]; - test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent.mins[2] + 1; - contents = GameBase.gi.pointcontents.pointcontents(test); + if ((ent.flags & Defines.FL_SWIM) != 0) + { + if (ent.waterlevel < 2) + { + test[0]= trace.endpos[0]; + test[1]= trace.endpos[1]; + test[2]= trace.endpos[2] + ent.mins[2] + 1; + contents= GameBase.gi.pointcontents.pointcontents(test); if ((contents & Defines.MASK_WATER) == 0) return false; } } - - if (trace.fraction == 1) { + + if (trace.fraction == 1) + { Math3D.VectorCopy(trace.endpos, ent.s.origin); - if (relink) { + if (relink) + { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return true; } - + if (ent.enemy == null) break; } - + return false; } - + // push down from a step height above the wished position if ((ent.monsterinfo.aiflags & Defines.AI_NOSTEP) == 0) - stepsize = GameBase.STEPSIZE; + stepsize= GameBase.STEPSIZE; else - stepsize = 1; - + stepsize= 1; + neworg[2] += stepsize; Math3D.VectorCopy(neworg, end); end[2] -= stepsize * 2; - - trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); - + + trace= GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); + if (trace.allsolid) return false; - - if (trace.startsolid) { + + if (trace.startsolid) + { neworg[2] -= stepsize; - trace = GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); + trace= GameBase.gi.trace(neworg, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } - + // don't go in to water - if (ent.waterlevel == 0) { - test[0] = trace.endpos[0]; - test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent.mins[2] + 1; - contents = GameBase.gi.pointcontents.pointcontents(test); - + if (ent.waterlevel == 0) + { + test[0]= trace.endpos[0]; + test[1]= trace.endpos[1]; + test[2]= trace.endpos[2] + ent.mins[2] + 1; + contents= GameBase.gi.pointcontents.pointcontents(test); + if ((contents & Defines.MASK_WATER) != 0) return false; } - - if (trace.fraction == 1) { + + if (trace.fraction == 1) + { // if monster had the ground pulled out, go ahead and fall - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) + { Math3D.VectorAdd(ent.s.origin, move, ent.s.origin); - if (relink) { + if (relink) + { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } - ent.groundentity = null; + ent.groundentity= null; return true; } - + return false; // walked off an edge } - + // check point traces down for dangling corners Math3D.VectorCopy(trace.endpos, ent.s.origin); - - if (!M.M_CheckBottom(ent)) { - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + + if (!M.M_CheckBottom(ent)) + { + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) + { // entity had floor mostly pulled out from underneath it // and is trying to correct - if (relink) { + if (relink) + { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } @@ -947,15 +1034,17 @@ public final class SV { Math3D.VectorCopy(oldorg, ent.s.origin); return false; } - - if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { + + if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) + { ent.flags &= ~Defines.FL_PARTIALGROUND; } - ent.groundentity = trace.ent; - ent.groundentity_linkcount = trace.ent.linkcount; - + ent.groundentity= trace.ent; + ent.groundentity_linkcount= trace.ent.linkcount; + // the move is ok - if (relink) { + if (relink) + { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } @@ -971,23 +1060,26 @@ public final class SV { ====================== */ - public static boolean SV_StepDirection(edict_t ent, float yaw, float dist) { - float[] move = { 0, 0, 0 }; - float[] oldorigin = { 0, 0, 0 }; + public static boolean SV_StepDirection(edict_t ent, float yaw, float dist) + { + float[] move= { 0, 0, 0 }; + float[] oldorigin= { 0, 0, 0 }; float delta; - - ent.ideal_yaw = yaw; + + ent.ideal_yaw= yaw; M.M_ChangeYaw(ent); - - yaw = (float) (yaw * Math.PI * 2 / 360); - move[0] = (float) Math.cos(yaw) * dist; - move[1] = (float) Math.sin(yaw) * dist; - move[2] = 0; - + + yaw= (float) (yaw * Math.PI * 2 / 360); + move[0]= (float) Math.cos(yaw) * dist; + move[1]= (float) Math.sin(yaw) * dist; + move[2]= 0; + Math3D.VectorCopy(ent.s.origin, oldorigin); - if (SV_movestep(ent, move, false)) { - delta = ent.s.angles[Defines.YAW] - ent.ideal_yaw; - if (delta > 45 && delta < 315) { // not turned far enough, so don't take the step + if (SV_movestep(ent, move, false)) + { + delta= ent.s.angles[Defines.YAW] - ent.ideal_yaw; + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step Math3D.VectorCopy(oldorigin, ent.s.origin); } GameBase.gi.linkentity(ent); @@ -1005,86 +1097,93 @@ public final class SV { ====================== */ - public static void SV_FixCheckBottom(edict_t ent) { + public static void SV_FixCheckBottom(edict_t ent) + { ent.flags |= Defines.FL_PARTIALGROUND; } - public static void SV_NewChaseDir(edict_t actor, edict_t enemy, float dist) { + public static void SV_NewChaseDir(edict_t actor, edict_t enemy, float dist) + { float deltax, deltay; - float d[] = { 0, 0, 0 }; + float d[]= { 0, 0, 0 }; float tdir, olddir, turnaround; - + //FIXME: how did we get here with no enemy if (enemy == null) { Com.DPrintf("SV_NewChaseDir without enemy!\n"); return; } - olddir = Math3D.anglemod((int) (actor.ideal_yaw / 45) * 45); - turnaround = Math3D.anglemod(olddir - 180); - - deltax = enemy.s.origin[0] - actor.s.origin[0]; - deltay = enemy.s.origin[1] - actor.s.origin[1]; + olddir= Math3D.anglemod((int) (actor.ideal_yaw / 45) * 45); + turnaround= Math3D.anglemod(olddir - 180); + + deltax= enemy.s.origin[0] - actor.s.origin[0]; + deltay= enemy.s.origin[1] - actor.s.origin[1]; if (deltax > 10) - d[1] = 0; + d[1]= 0; else if (deltax < -10) - d[1] = 180; + d[1]= 180; else - d[1] = GameBase.DI_NODIR; + d[1]= GameBase.DI_NODIR; if (deltay < -10) - d[2] = 270; + d[2]= 270; else if (deltay > 10) - d[2] = 90; + d[2]= 90; else - d[2] = GameBase.DI_NODIR; - + d[2]= GameBase.DI_NODIR; + // try direct route - if (d[1] != GameBase.DI_NODIR && d[2] != GameBase.DI_NODIR) { + if (d[1] != GameBase.DI_NODIR && d[2] != GameBase.DI_NODIR) + { if (d[1] == 0) - tdir = d[2] == 90 ? 45 : 315; + tdir= d[2] == 90 ? 45 : 315; else - tdir = d[2] == 90 ? 135 : 215; - + tdir= d[2] == 90 ? 135 : 215; + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } - + // try other directions - if (((Lib.rand() & 3) & 1) != 0 || Math.abs(deltay) > Math.abs(deltax)) { - tdir = d[1]; - d[1] = d[2]; - d[2] = tdir; + if (((Lib.rand() & 3) & 1) != 0 || Math.abs(deltay) > Math.abs(deltax)) + { + tdir= d[1]; + d[1]= d[2]; + d[2]= tdir; } - + if (d[1] != GameBase.DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist)) return; - + if (d[2] != GameBase.DI_NODIR && d[2] != turnaround && SV_StepDirection(actor, d[2], dist)) return; - + /* there is no direct path to the player, so pick another direction */ - + if (olddir != GameBase.DI_NODIR && SV_StepDirection(actor, olddir, dist)) return; - - if ((Lib.rand() & 1) != 0) /*randomly determine direction of search*/ { - for (tdir = 0; tdir <= 315; tdir += 45) + + if ((Lib.rand() & 1) != 0) /*randomly determine direction of search*/ + { + for (tdir= 0; tdir <= 315; tdir += 45) if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; - } else { - for (tdir = 315; tdir >= 0; tdir -= 45) + } + else + { + for (tdir= 315; tdir >= 0; tdir -= 45) if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } - + if (turnaround != GameBase.DI_NODIR && SV_StepDirection(actor, turnaround, dist)) return; - - actor.ideal_yaw = olddir; // can't move - + + actor.ideal_yaw= olddir; // can't move + // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all - + if (!M.M_CheckBottom(actor)) SV_FixCheckBottom(actor); } @@ -1094,11 +1193,13 @@ public final class SV { SV_CloseEnough ====================== - *///ok - public static boolean SV_CloseEnough(edict_t ent, edict_t goal, float dist) { + */ //ok + public static boolean SV_CloseEnough(edict_t ent, edict_t goal, float dist) + { int i; - - for (i = 0; i < 3; i++) { + + for (i= 0; i < 3; i++) + { if (goal.absmin[i] > ent.absmax[i] + dist) return false; if (goal.absmax[i] < ent.absmin[i] - dist) |