📄 sv.java
字号:
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 (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if ((ent.svflags & Defines.SVF_MONSTER) != 0) mask = Defines.MASK_MONSTERSOLID; else 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); } /** * Called by monster program code. The move will be adjusted for slopes and * stairs, but if the move isn't possible, no move is done, false is * returned, and pr_global_struct.trace_normal is set to the normal of the * blocking wall. */ // 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) { float dz; 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 }; 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) { // try one move with vertical motion, then one without for (i = 0; i < 2; i++) { Math3D.VectorAdd(ent.s.origin, move, neworg); 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) { if (dz > 40) neworg[2] -= 8; if (!((ent.flags & Defines.FL_SWIM) != 0 && (ent.waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else { if (dz > 8) neworg[2] -= 8; else if (dz > 0) neworg[2] -= dz; else if (dz < -8) neworg[2] += 8; else neworg[2] += dz; } } 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 ((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 ((contents & Defines.MASK_WATER) == 0) return false; } } if (trace.fraction == 1) { Math3D.VectorCopy(trace.endpos, ent.s.origin); 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; else 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); if (trace.allsolid) return false; if (trace.startsolid) { neworg[2] -= stepsize; 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 ((contents & Defines.MASK_WATER) != 0) return false; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { Math3D.VectorAdd(ent.s.origin, move, ent.s.origin); if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } 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) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return true; } Math3D.VectorCopy(oldorg, ent.s.origin); return false; } if ((ent.flags & Defines.FL_PARTIALGROUND) != 0) { ent.flags &= ~Defines.FL_PARTIALGROUND; } ent.groundentity = trace.ent; ent.groundentity_linkcount = trace.ent.linkcount; // the move is ok if (relink) { GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); } return true; } /** * Turns to the movement direction, and walks the current distance if facing * it. */ 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; 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; 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 Math3D.VectorCopy(oldorigin, ent.s.origin); } GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); return true; } GameBase.gi.linkentity(ent); GameBase.G_TouchTriggers(ent); return false; } /** * SV_FixCheckBottom * */ 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) { float deltax, deltay; 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]; if (deltax > 10) d[1] = 0; else if (deltax < -10) d[1] = 180; else d[1] = DI_NODIR; if (deltay < -10) d[2] = 270; else if (deltay > 10) d[2] = 90; else d[2] = DI_NODIR; // try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { if (d[1] == 0) tdir = d[2] == 90 ? 45 : 315; else 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 (d[1] != DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist)) return; if (d[2] != 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 != 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 (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } else { for (tdir = 315; tdir >= 0; tdir -= 45) if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist)) return; 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); } /** * SV_CloseEnough - returns true if distance between 2 ents is smaller than * given dist. */ public static boolean SV_CloseEnough(edict_t ent, edict_t goal, float dist) { int 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) return false; } return true; } public static int DI_NODIR = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -