aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/client/M.java
diff options
context:
space:
mode:
authorRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
committerRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
commitc4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 (patch)
tree7c9439ab1d9f5a4fd61bd57c755069007b23e0b6 /src/jake2/client/M.java
parentbcb4ac6eefb425d5b0a90009da506361d5739e75 (diff)
major refactoring in game, server and client package
Diffstat (limited to 'src/jake2/client/M.java')
-rw-r--r--src/jake2/client/M.java1157
1 files changed, 540 insertions, 617 deletions
diff --git a/src/jake2/client/M.java b/src/jake2/client/M.java
index 3e076a6..2ea0d01 100644
--- a/src/jake2/client/M.java
+++ b/src/jake2/client/M.java
@@ -2,27 +2,27 @@
* M.java
* Copyright (C) 2003
*
- * $Id: M.java,v 1.4 2004-07-08 20:56:50 hzi Exp $
+ * $Id: M.java,v 1.5 2004-09-22 19:22:07 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ Copyright (C) 1997-2001 Id Software, Inc.
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU General Public License for more details.
+ See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
+ */
package jake2.client;
import jake2.Defines;
@@ -35,606 +35,529 @@ import jake2.util.Math3D;
/**
* M
*/
-public final class M
-{
-
- public static void M_CheckGround(edict_t ent)
- {
- float[] point = { 0, 0, 0 };
- trace_t trace;
-
- if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0)
- return;
-
- if (ent.velocity[2] > 100)
- {
- ent.groundentity = null;
- return;
- }
-
- // if the hull point one-quarter unit down is solid the entity is on ground
- point[0] = ent.s.origin[0];
- point[1] = ent.s.origin[1];
- point[2] = ent.s.origin[2] - 0.25f;
-
- trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent, Defines.MASK_MONSTERSOLID);
-
- // check steepness
- if (trace.plane.normal[2] < 0.7 && !trace.startsolid)
- {
- ent.groundentity = null;
- return;
- }
-
- // ent.groundentity = trace.ent;
- // ent.groundentity_linkcount = trace.ent.linkcount;
- // if (!trace.startsolid && !trace.allsolid)
- // VectorCopy (trace.endpos, ent.s.origin);
- if (!trace.startsolid && !trace.allsolid)
- {
- Math3D.VectorCopy(trace.endpos, ent.s.origin);
- ent.groundentity = trace.ent;
- ent.groundentity_linkcount = trace.ent.linkcount;
- ent.velocity[2] = 0;
- }
- }
-
- public static boolean M_CheckBottom(edict_t ent)
- {
- float[] mins = { 0, 0, 0 };
- float[] maxs = { 0, 0, 0 };
- float[] start = { 0, 0, 0 };
- float[] stop = { 0, 0, 0 };
-
- trace_t trace;
- int x, y;
- float mid, bottom;
-
- Math3D.VectorAdd(ent.s.origin, ent.mins, mins);
- Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs);
-
- // if all of the points under the corners are solid world, don't bother
- // with the tougher checks
- // the corners must be within 16 of the midpoint
- start[2] = mins[2] - 1;
- for (x = 0; x <= 1; x++)
- for (y = 0; y <= 1; y++)
- {
- start[0] = x != 0 ? maxs[0] : mins[0];
- start[1] = y != 0 ? maxs[1] : mins[1];
- if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID)
- {
- GameBase.c_no++;
- //
- // check it for real...
- //
- start[2] = mins[2];
-
- // the midpoint must be within 16 of the bottom
- start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
- start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
- stop[2] = start[2] - 2 * GameBase.STEPSIZE;
- trace = GameBase.gi.trace(start, GameBase.vec3_origin, GameBase.vec3_origin, stop, ent, Defines.MASK_MONSTERSOLID);
-
- if (trace.fraction == 1.0)
- return false;
- mid = bottom = trace.endpos[2];
-
- // the corners must be within 16 of the midpoint
- for (x = 0; x <= 1; x++)
- for (y = 0; y <= 1; y++)
- {
- start[0] = stop[0] = x != 0 ? maxs[0] : mins[0];
- start[1] = stop[1] = y != 0 ? maxs[1] : mins[1];
-
- trace =
- GameBase.gi.trace(
- start,
- GameBase.vec3_origin,
- GameBase.vec3_origin,
- stop,
- ent,
- Defines.MASK_MONSTERSOLID);
-
- if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
- bottom = trace.endpos[2];
- if (trace.fraction == 1.0 || mid - trace.endpos[2] > GameBase.STEPSIZE)
- return false;
- }
-
- GameBase.c_yes++;
- return true;
- }
- }
-
- GameBase.c_yes++;
- return true; // we got out easy
- }
-
- /*
- ===============
- M_ChangeYaw
-
- ===============
- */ //ok
- public static void M_ChangeYaw(edict_t ent)
- {
- float ideal;
- float current;
- float move;
- float speed;
-
- current = Math3D.anglemod(ent.s.angles[Defines.YAW]);
- ideal = ent.ideal_yaw;
-
- if (current == ideal)
- return;
-
- move = ideal - current;
- speed = ent.yaw_speed;
- if (ideal > current)
- {
- if (move >= 180)
- move = move - 360;
- }
- else
- {
- if (move <= -180)
- move = move + 360;
- }
- if (move > 0)
- {
- if (move > speed)
- move = speed;
- }
- else
- {
- if (move < -speed)
- move = -speed;
- }
-
- ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move);
- }
-
- /*
- ======================
- M_MoveToGoal
- ======================
- */ // ok
- public static void M_MoveToGoal(edict_t ent, float dist)
- {
- edict_t goal = ent.goalentity;
-
- if (ent.groundentity == null && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
- return;
-
- // if the next step hits the enemy, return immediately
- if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist))
- return;
-
- // bump around...
- if ((Lib.rand() & 3) == 1 || !SV.SV_StepDirection(ent, ent.ideal_yaw, dist))
- {
- if (ent.inuse)
- SV.SV_NewChaseDir(ent, goal, dist);
- }
- }
-
- /*
- ===============
- M_walkmove
- ===============
- */
- public static boolean M_walkmove(edict_t ent, float yaw, float dist)
- {
- float[] move = { 0, 0, 0 };
-
- if ((ent.groundentity == null) && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
- return false;
-
- yaw = (float) (yaw * Math.PI * 2 / 360);
-
- move[0] = (float) Math.cos(yaw) * dist;
- move[1] = (float) Math.sin(yaw) * dist;
- move[2] = 0;
-
- return SV.SV_movestep(ent, move, true);
- }
-
- public static void M_CatagorizePosition(edict_t ent)
- {
- float[] point = { 0, 0, 0 };
- int cont;
-
- //
- // get waterlevel
- //
- point[0] = ent.s.origin[0];
- point[1] = ent.s.origin[1];
- point[2] = ent.s.origin[2] + ent.mins[2] + 1;
- cont = Game.gi.pointcontents.pointcontents(point);
-
- if (0 == (cont & Defines.MASK_WATER))
- {
- ent.waterlevel = 0;
- ent.watertype = 0;
- return;
- }
-
- ent.watertype = cont;
- ent.waterlevel = 1;
- point[2] += 26;
- cont = GameBase.gi.pointcontents.pointcontents(point);
- if (0 == (cont & Defines.MASK_WATER))
- return;
-
- ent.waterlevel = 2;
- point[2] += 22;
- cont = GameBase.gi.pointcontents.pointcontents(point);
- if (0 != (cont & Defines.MASK_WATER))
- ent.waterlevel = 3;
- }
-
- public static void M_WorldEffects(edict_t ent)
- {
- int dmg;
-
- if (ent.health > 0)
- {
- if (0 == (ent.flags & Defines.FL_SWIM))
- {
- if (ent.waterlevel < 3)
- {
- ent.air_finished = GameBase.level.time + 12;
- }
- else if (ent.air_finished < GameBase.level.time)
- {
- // drown!
- if (ent.pain_debounce_time < GameBase.level.time)
- {
- dmg = (int) (2f + 2f * Math.floor(GameBase.level.time - ent.air_finished));
- if (dmg > 15)
- dmg = 15;
- GameUtil.T_Damage(
- ent,
- GameBase.g_edicts[0],
- GameBase.g_edicts[0],
- GameBase.vec3_origin,
- ent.s.origin,
- GameBase.vec3_origin,
- dmg,
- 0,
- Defines.DAMAGE_NO_ARMOR,
- Defines.MOD_WATER);
- ent.pain_debounce_time = GameBase.level.time + 1;
- }
- }
- }
- else
- {
- if (ent.waterlevel > 0)
- {
- ent.air_finished = GameBase.level.time + 9;
- }
- else if (ent.air_finished < GameBase.level.time)
- {
- // suffocate!
- if (ent.pain_debounce_time < GameBase.level.time)
- {
- dmg = (int) (2 + 2 * Math.floor(GameBase.level.time - ent.air_finished));
- if (dmg > 15)
- dmg = 15;
- GameUtil.T_Damage(
- ent,
- GameBase.g_edicts[0],
- GameBase.g_edicts[0],
- GameBase.vec3_origin,
- ent.s.origin,
- GameBase.vec3_origin,
- dmg,
- 0,
- Defines.DAMAGE_NO_ARMOR,
- Defines.MOD_WATER);
- ent.pain_debounce_time = GameBase.level.time + 1;
- }
- }
- }
- }
-
- if (ent.waterlevel == 0)
- {
- if ((ent.flags & Defines.FL_INWATER) != 0)
- {
- GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_out.wav"), 1, Defines.ATTN_NORM, 0);
- ent.flags &= ~Defines.FL_INWATER;
- }
- return;
- }
-
- if ((ent.watertype & Defines.CONTENTS_LAVA) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_LAVA))
- {
- if (ent.damage_debounce_time < GameBase.level.time)
- {
- ent.damage_debounce_time = GameBase.level.time + 0.2f;
- GameUtil.T_Damage(
- ent,
- GameBase.g_edicts[0],
- GameBase.g_edicts[0],
- GameBase.vec3_origin,
- ent.s.origin,
- GameBase.vec3_origin,
- 10 * ent.waterlevel,
- 0,
- 0,
- Defines.MOD_LAVA);
- }
- }
- if ((ent.watertype & Defines.CONTENTS_SLIME) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_SLIME))
- {
- if (ent.damage_debounce_time < GameBase.level.time)
- {
- ent.damage_debounce_time = GameBase.level.time + 1;
- GameUtil.T_Damage(
- ent,
- GameBase.g_edicts[0],
- GameBase.g_edicts[0],
- GameBase.vec3_origin,
- ent.s.origin,
- GameBase.vec3_origin,
- 4 * ent.waterlevel,
- 0,
- 0,
- Defines.MOD_SLIME);
- }
- }
-
- if (0 == (ent.flags & Defines.FL_INWATER))
- {
- if (0 == (ent.svflags & Defines.SVF_DEADMONSTER))
- {
- if ((ent.watertype & Defines.CONTENTS_LAVA) != 0)
- if (Globals.rnd.nextFloat() <= 0.5)
- GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava1.wav"), 1, Defines.ATTN_NORM, 0);
- else
- GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava2.wav"), 1, Defines.ATTN_NORM, 0);
- else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0)
- GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0);
- else if ((ent.watertype & Defines.CONTENTS_WATER) != 0)
- GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0);
- }
-
- ent.flags |= Defines.FL_INWATER;
- ent.damage_debounce_time = 0;
- }
- }
-
- public static EntThinkAdapter M_droptofloor = new EntThinkAdapter()
- {
- public boolean think(edict_t ent)
- {
- float[] end = { 0, 0, 0 };
- trace_t trace;
-
- ent.s.origin[2] += 1;
- Math3D.VectorCopy(ent.s.origin, end);
- end[2] -= 256;
-
- trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID);
-
- if (trace.fraction == 1 || trace.allsolid)
- return true;
-
- Math3D.VectorCopy(trace.endpos, ent.s.origin);
-
- GameBase.gi.linkentity(ent);
- M.M_CheckGround(ent);
- M_CatagorizePosition(ent);
- return true;
- }
- };
-
- public static void M_SetEffects(edict_t ent)
- {
- ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN);
- ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE);
-
- if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0)
- {
- ent.s.effects |= Defines.EF_COLOR_SHELL;
- ent.s.renderfx |= Defines.RF_SHELL_RED;
- }
-
- if (ent.health <= 0)
- return;
-
- if (ent.powerarmor_time > GameBase.level.time)
- {
- if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN)
- {
- ent.s.effects |= Defines.EF_POWERSCREEN;
- }
- else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD)
- {
- ent.s.effects |= Defines.EF_COLOR_SHELL;
- ent.s.renderfx |= Defines.RF_SHELL_GREEN;
- }
- }
- };
-
- //ok
- public static void M_MoveFrame(edict_t self)
- {
- mmove_t move; //ptr
- int index;
-
- move = self.monsterinfo.currentmove;
- self.nextthink = GameBase.level.time + Defines.FRAMETIME;
-
- if ((self.monsterinfo.nextframe != 0)
- && (self.monsterinfo.nextframe >= move.firstframe)
- && (self.monsterinfo.nextframe <= move.lastframe))
- {
- self.s.frame = self.monsterinfo.nextframe;
- self.monsterinfo.nextframe = 0;
- }
- else
- {
- if (self.s.frame == move.lastframe)
- {
- if (move.endfunc != null)
- {
- move.endfunc.think(self);
-
- // regrab move, endfunc is very likely to change it
- move = self.monsterinfo.currentmove;
-
- // check for death
- if ((self.svflags & Defines.SVF_DEADMONSTER) != 0)
- return;
- }
- }
-
- if (self.s.frame < move.firstframe || self.s.frame > move.lastframe)
- {
- self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME;
- self.s.frame = move.firstframe;
- }
- else
- {
- if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME))
- {
- self.s.frame++;
- if (self.s.frame > move.lastframe)
- self.s.frame = move.firstframe;
- }
- }
- }
-
- index = self.s.frame - move.firstframe;
- if (move.frame[index].ai != null)
- if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME))
- move.frame[index].ai.ai(self, move.frame[index].dist * self.monsterinfo.scale);
- else
- move.frame[index].ai.ai(self, 0);
-
- if (move.frame[index].think != null)
- move.frame[index].think.think(self);
- }
-
- public static void M_ReactToDamage(edict_t targ, edict_t attacker)
- {
- if ((null != attacker.client) && 0 != (attacker.svflags & Defines.SVF_MONSTER))
- return;
-
- if (attacker == targ || attacker == targ.enemy)
- return;
-
- // if we are a good guy monster and our attacker is a player
- // or another good guy, do not get mad at them
- if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY))
- {
- if (attacker.client != null || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0)
- return;
- }
-
- // we now know that we are not both good guys
-
- // if attacker is a client, get mad at them because he's good and we're not
- if (attacker.client != null)
- {
- targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
-
- // this can only happen in coop (both new and old enemies are clients)
- // only switch if can't see the current enemy
- if (targ.enemy != null && targ.enemy.client != null)
- {
- if (GameUtil.visible(targ, targ.enemy))
- {
- targ.oldenemy = attacker;
- return;
- }
- targ.oldenemy = targ.enemy;
- }
- targ.enemy = attacker;
- if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
- GameUtil.FoundTarget(targ);
- return;
- }
-
- // it's the same base (walk/swim/fly) type and a different classname and it's not a tank
- // (they spray too much), get mad at them
- if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM)))
- && (Lib.strcmp(targ.classname, attacker.classname) != 0)
- && (Lib.strcmp(attacker.classname, "monster_tank") != 0)
- && (Lib.strcmp(attacker.classname, "monster_supertank") != 0)
- && (Lib.strcmp(attacker.classname, "monster_makron") != 0)
- && (Lib.strcmp(attacker.classname, "monster_jorg") != 0))
- {
- if (targ.enemy != null && targ.enemy.client != null)
- targ.oldenemy = targ.enemy;
- targ.enemy = attacker;
- if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
- GameUtil.FoundTarget(targ);
- }
- // if they *meant* to shoot us, then shoot back
- else if (attacker.enemy == targ)
- {
- if (targ.enemy != null && targ.enemy.client != null)
- targ.oldenemy = targ.enemy;
- targ.enemy = attacker;
- if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
- GameUtil.FoundTarget(targ);
- }
- // otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
- else if (attacker.enemy != null && attacker.enemy != targ)
- {
- if (targ.enemy != null && targ.enemy.client != null)
- targ.oldenemy = targ.enemy;
- targ.enemy = attacker.enemy;
- if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
- GameUtil.FoundTarget(targ);
- }
- }
- /** Stops the Flies. */
- public static EntThinkAdapter M_FliesOff = new EntThinkAdapter()
- {
- public boolean think(edict_t self)
- {
- self.s.effects &= ~Defines.EF_FLIES;
- self.s.sound = 0;
- return true;
- }
- };
- /** Starts the Flies as setting the animation flag in the entity. */
- public static EntThinkAdapter M_FliesOn = new EntThinkAdapter()
- {
- public boolean think(edict_t self)
- {
- if (self.waterlevel != 0)
- return true;
-
- self.s.effects |= Defines.EF_FLIES;
- self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav");
- self.think = M_FliesOff;
- self.nextthink = GameBase.level.time + 60;
- return true;
- }
- };
- /** Adds some flies after a random time */
- public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter()
- {
- public boolean think(edict_t self)
- {
-
- if (self.waterlevel != 0)
- return true;
-
- if (Globals.rnd.nextFloat() > 0.5)
- return true;
-
- self.think = M_FliesOn;
- self.nextthink = GameBase.level.time + 5 + 10 * Globals.rnd.nextFloat();
- return true;
- }
- };
-}
+public final class M {
+
+ public static void M_CheckGround(edict_t ent) {
+ float[] point = { 0, 0, 0 };
+ trace_t trace;
+
+ if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0)
+ return;
+
+ if (ent.velocity[2] > 100) {
+ ent.groundentity = null;
+ return;
+ }
+
+ // if the hull point one-quarter unit down is solid the entity is on
+ // ground
+ point[0] = ent.s.origin[0];
+ point[1] = ent.s.origin[1];
+ point[2] = ent.s.origin[2] - 0.25f;
+
+ trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent,
+ Defines.MASK_MONSTERSOLID);
+
+ // check steepness
+ if (trace.plane.normal[2] < 0.7 && !trace.startsolid) {
+ ent.groundentity = null;
+ return;
+ }
+
+ // ent.groundentity = trace.ent;
+ // ent.groundentity_linkcount = trace.ent.linkcount;
+ // if (!trace.startsolid && !trace.allsolid)
+ // VectorCopy (trace.endpos, ent.s.origin);
+ if (!trace.startsolid && !trace.allsolid) {
+ Math3D.VectorCopy(trace.endpos, ent.s.origin);
+ ent.groundentity = trace.ent;
+ ent.groundentity_linkcount = trace.ent.linkcount;
+ ent.velocity[2] = 0;
+ }
+ }
+
+ public static boolean M_CheckBottom(edict_t ent) {
+ float[] mins = { 0, 0, 0 };
+ float[] maxs = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ float[] stop = { 0, 0, 0 };
+
+ trace_t trace;
+ int x, y;
+ float mid, bottom;
+
+ Math3D.VectorAdd(ent.s.origin, ent.mins, mins);
+ Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs);
+
+ // if all of the points under the corners are solid world, don't bother
+ // with the tougher checks
+ // the corners must be within 16 of the midpoint
+ start[2] = mins[2] - 1;
+ for (x = 0; x <= 1; x++)
+ for (y = 0; y <= 1; y++) {
+ start[0] = x != 0 ? maxs[0] : mins[0];
+ start[1] = y != 0 ? maxs[1] : mins[1];
+ if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID) {
+ GameBase.c_no++;
+ //
+ // check it for real...
+ //
+ start[2] = mins[2];
+
+ // the midpoint must be within 16 of the bottom
+ start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
+ start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
+ stop[2] = start[2] - 2 * GameBase.STEPSIZE;
+ trace = GameBase.gi.trace(start, Globals.vec3_origin,
+ Globals.vec3_origin, stop, ent,
+ Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction == 1.0)
+ return false;
+ mid = bottom = trace.endpos[2];
+
+ // the corners must be within 16 of the midpoint
+ for (x = 0; x <= 1; x++)
+ for (y = 0; y <= 1; y++) {
+ start[0] = stop[0] = x != 0 ? maxs[0] : mins[0];
+ start[1] = stop[1] = y != 0 ? maxs[1] : mins[1];
+
+ trace = GameBase.gi.trace(start,
+ Globals.vec3_origin, Globals.vec3_origin,
+ stop, ent, Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction != 1.0
+ && trace.endpos[2] > bottom)
+ bottom = trace.endpos[2];
+ if (trace.fraction == 1.0
+ || mid - trace.endpos[2] > GameBase.STEPSIZE)
+ return false;
+ }
+
+ GameBase.c_yes++;
+ return true;
+ }
+ }
+
+ GameBase.c_yes++;
+ return true; // we got out easy
+ }
+
+ /*
+ * =============== M_ChangeYaw
+ *
+ * ===============
+ *///ok
+ public static void M_ChangeYaw(edict_t ent) {
+ float ideal;
+ float current;
+ float move;
+ float speed;
+
+ current = Math3D.anglemod(ent.s.angles[Defines.YAW]);
+ ideal = ent.ideal_yaw;
+
+ if (current == ideal)
+ return;
+
+ move = ideal - current;
+ speed = ent.yaw_speed;
+ if (ideal > current) {
+ if (move >= 180)
+ move = move - 360;
+ } else {
+ if (move <= -180)
+ move = move + 360;
+ }
+ if (move > 0) {
+ if (move > speed)
+ move = speed;
+ } else {
+ if (move < -speed)
+ move = -speed;
+ }
+
+ ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move);
+ }
+
+ /*
+ * ====================== M_MoveToGoal ======================
+ */// ok
+ public static void M_MoveToGoal(edict_t ent, float dist) {
+ edict_t goal = ent.goalentity;
+
+ if (ent.groundentity == null
+ && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
+ return;
+
+ // if the next step hits the enemy, return immediately
+ if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist))
+ return;
+
+ // bump around...
+ if ((Lib.rand() & 3) == 1
+ || !SV.SV_StepDirection(ent, ent.ideal_yaw, dist)) {
+ if (ent.inuse)
+ SV.SV_NewChaseDir(ent, goal, dist);
+ }
+ }
+
+ /*
+ * =============== M_walkmove ===============
+ */
+ public static boolean M_walkmove(edict_t ent, float yaw, float dist) {
+ float[] move = { 0, 0, 0 };
+
+ if ((ent.groundentity == null)
+ && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
+ return false;
+
+ yaw = (float) (yaw * Math.PI * 2 / 360);
+
+ move[0] = (float) Math.cos(yaw) * dist;
+ move[1] = (float) Math.sin(yaw) * dist;
+ move[2] = 0;
+
+ return SV.SV_movestep(ent, move, true);
+ }
+
+ public static void M_CatagorizePosition(edict_t ent) {
+ float[] point = { 0, 0, 0 };
+ int cont;
+
+ //
+ // get waterlevel
+ //
+ point[0] = ent.s.origin[0];
+ point[1] = ent.s.origin[1];
+ point[2] = ent.s.origin[2] + ent.mins[2] + 1;
+ cont = GameBase.gi.pointcontents.pointcontents(point);
+
+ if (0 == (cont & Defines.MASK_WATER)) {
+ ent.waterlevel = 0;
+ ent.watertype = 0;
+ return;
+ }
+
+ ent.watertype = cont;
+ ent.waterlevel = 1;
+ point[2] += 26;
+ cont = GameBase.gi.pointcontents.pointcontents(point);
+ if (0 == (cont & Defines.MASK_WATER))
+ return;
+
+ ent.waterlevel = 2;
+ point[2] += 22;
+ cont = GameBase.gi.pointcontents.pointcontents(point);
+ if (0 != (cont & Defines.MASK_WATER))
+ ent.waterlevel = 3;
+ }
+
+ public static void M_WorldEffects(edict_t ent) {
+ int dmg;
+
+ if (ent.health > 0) {
+ if (0 == (ent.flags & Defines.FL_SWIM)) {
+ if (ent.waterlevel < 3) {
+ ent.air_finished = GameBase.level.time + 12;
+ } else if (ent.air_finished < GameBase.level.time) {
+ // drown!
+ if (ent.pain_debounce_time < GameBase.level.time) {
+ dmg = (int) (2f + 2f * Math.floor(GameBase.level.time
+ - ent.air_finished));
+ if (dmg > 15)
+ dmg = 15;
+ GameUtil.T_Damage(ent, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ ent.s.origin, Globals.vec3_origin, dmg, 0,
+ Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER);
+ ent.pain_debounce_time = GameBase.level.time + 1;
+ }
+ }
+ } else {
+ if (ent.waterlevel > 0) {
+ ent.air_finished = GameBase.level.time + 9;
+ } else if (ent.air_finished < GameBase.level.time) {
+ // suffocate!
+ if (ent.pain_debounce_time < GameBase.level.time) {
+ dmg = (int) (2 + 2 * Math.floor(GameBase.level.time
+ - ent.air_finished));
+ if (dmg > 15)
+ dmg = 15;
+ GameUtil.T_Damage(ent, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ ent.s.origin, Globals.vec3_origin, dmg, 0,
+ Defines.DAMAGE_NO_ARMOR, Defines.MOD_WATER);
+ ent.pain_debounce_time = GameBase.level.time + 1;
+ }
+ }
+ }
+ }
+
+ if (ent.waterlevel == 0) {
+ if ((ent.flags & Defines.FL_INWATER) != 0) {
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/watr_out.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ ent.flags &= ~Defines.FL_INWATER;
+ }
+ return;
+ }
+
+ if ((ent.watertype & Defines.CONTENTS_LAVA) != 0
+ && 0 == (ent.flags & Defines.FL_IMMUNE_LAVA)) {
+ if (ent.damage_debounce_time < GameBase.level.time) {
+ ent.damage_debounce_time = GameBase.level.time + 0.2f;
+ GameUtil.T_Damage(ent, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ ent.s.origin, Globals.vec3_origin, 10 * ent.waterlevel,
+ 0, 0, Defines.MOD_LAVA);
+ }
+ }
+ if ((ent.watertype & Defines.CONTENTS_SLIME) != 0
+ && 0 == (ent.flags & Defines.FL_IMMUNE_SLIME)) {
+ if (ent.damage_debounce_time < GameBase.level.time) {
+ ent.damage_debounce_time = GameBase.level.time + 1;
+ GameUtil.T_Damage(ent, GameBase.g_edicts[0],
+ GameBase.g_edicts[0], Globals.vec3_origin,
+ ent.s.origin, Globals.vec3_origin, 4 * ent.waterlevel,
+ 0, 0, Defines.MOD_SLIME);
+ }
+ }
+
+ if (0 == (ent.flags & Defines.FL_INWATER)) {
+ if (0 == (ent.svflags & Defines.SVF_DEADMONSTER)) {
+ if ((ent.watertype & Defines.CONTENTS_LAVA) != 0)
+ if (Globals.rnd.nextFloat() <= 0.5)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/lava1.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/lava2.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/watr_in.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ else if ((ent.watertype & Defines.CONTENTS_WATER) != 0)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi
+ .soundindex("player/watr_in.wav"), 1,
+ Defines.ATTN_NORM, 0);
+ }
+
+ ent.flags |= Defines.FL_INWATER;
+ ent.damage_debounce_time = 0;
+ }
+ }
+
+ public static EntThinkAdapter M_droptofloor = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] end = { 0, 0, 0 };
+ trace_t trace;
+
+ ent.s.origin[2] += 1;
+ Math3D.VectorCopy(ent.s.origin, end);
+ end[2] -= 256;
+
+ trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end,
+ ent, Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction == 1 || trace.allsolid)
+ return true;
+
+ Math3D.VectorCopy(trace.endpos, ent.s.origin);
+
+ GameBase.gi.linkentity(ent);
+ M.M_CheckGround(ent);
+ M_CatagorizePosition(ent);
+ return true;
+ }
+ };
+
+ public static void M_SetEffects(edict_t ent) {
+ ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN);
+ ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE);
+
+ if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= Defines.RF_SHELL_RED;
+ }
+
+ if (ent.health <= 0)
+ return;
+
+ if (ent.powerarmor_time > GameBase.level.time) {
+ if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN) {
+ ent.s.effects |= Defines.EF_POWERSCREEN;
+ } else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= Defines.RF_SHELL_GREEN;
+ }
+ }
+ };
+
+ //ok
+ public static void M_MoveFrame(edict_t self) {
+ mmove_t move; //ptr
+ int index;
+
+ move = self.monsterinfo.currentmove;
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+
+ if ((self.monsterinfo.nextframe != 0)
+ && (self.monsterinfo.nextframe >= move.firstframe)
+ && (self.monsterinfo.nextframe <= move.lastframe)) {
+ self.s.frame = self.monsterinfo.nextframe;
+ self.monsterinfo.nextframe = 0;
+ } else {
+ if (self.s.frame == move.lastframe) {
+ if (move.endfunc != null) {
+ move.endfunc.think(self);
+
+ // regrab move, endfunc is very likely to change it
+ move = self.monsterinfo.currentmove;
+
+ // check for death
+ if ((self.svflags & Defines.SVF_DEADMONSTER) != 0)
+ return;
+ }
+ }
+
+ if (self.s.frame < move.firstframe || self.s.frame > move.lastframe) {
+ self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME;
+ self.s.frame = move.firstframe;
+ } else {
+ if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) {
+ self.s.frame++;
+ if (self.s.frame > move.lastframe)
+ self.s.frame = move.firstframe;
+ }
+ }
+ }
+
+ index = self.s.frame - move.firstframe;
+ if (move.frame[index].ai != null)
+ if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME))
+ move.frame[index].ai.ai(self, move.frame[index].dist
+ * self.monsterinfo.scale);
+ else
+ move.frame[index].ai.ai(self, 0);
+
+ if (move.frame[index].think != null)
+ move.frame[index].think.think(self);
+ }
+
+ public static void M_ReactToDamage(edict_t targ, edict_t attacker) {
+ if ((null != attacker.client)
+ && 0 != (attacker.svflags & Defines.SVF_MONSTER))
+ return;
+
+ if (attacker == targ || attacker == targ.enemy)
+ return;
+
+ // if we are a good guy monster and our attacker is a player
+ // or another good guy, do not get mad at them
+ if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
+ if (attacker.client != null
+ || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0)
+ return;
+ }
+
+ // we now know that we are not both good guys
+
+ // if attacker is a client, get mad at them because he's good and we're
+ // not
+ if (attacker.client != null) {
+ targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
+
+ // this can only happen in coop (both new and old enemies are
+ // clients)
+ // only switch if can't see the current enemy
+ if (targ.enemy != null && targ.enemy.client != null) {
+ if (GameUtil.visible(targ, targ.enemy)) {
+ targ.oldenemy = attacker;
+ return;
+ }
+ targ.oldenemy = targ.enemy;
+ }
+ targ.enemy = attacker;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ return;
+ }
+
+ // it's the same base (walk/swim/fly) type and a different classname and
+ // it's not a tank
+ // (they spray too much), get mad at them
+ if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM)))
+ && (Lib.strcmp(targ.classname, attacker.classname) != 0)
+ && (Lib.strcmp(attacker.classname, "monster_tank") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_supertank") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_makron") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_jorg") != 0)) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ // if they *meant* to shoot us, then shoot back
+ else if (attacker.enemy == targ) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ // otherwise get mad at whoever they are mad at (help our buddy) unless
+ // it is us!
+ else if (attacker.enemy != null && attacker.enemy != targ) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker.enemy;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ }
+
+ /** Stops the Flies. */
+ public static EntThinkAdapter M_FliesOff = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.s.effects &= ~Defines.EF_FLIES;
+ self.s.sound = 0;
+ return true;
+ }
+ };
+
+ /** Starts the Flies as setting the animation flag in the entity. */
+ public static EntThinkAdapter M_FliesOn = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.waterlevel != 0)
+ return true;
+
+ self.s.effects |= Defines.EF_FLIES;
+ self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav");
+ self.think = M_FliesOff;
+ self.nextthink = GameBase.level.time + 60;
+ return true;
+ }
+ };
+
+ /** Adds some flies after a random time */
+ public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (self.waterlevel != 0)
+ return true;
+
+ if (Globals.rnd.nextFloat() > 0.5)
+ return true;
+
+ self.think = M_FliesOn;
+ self.nextthink = GameBase.level.time + 5 + 10
+ * Globals.rnd.nextFloat();
+ return true;
+ }
+ };
+} \ No newline at end of file