void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) { float deltax,deltay; float d[3]; float tdir, olddir, turnaround; olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 ); turnaround = anglemod(olddir - 180); deltax = enemy->v.origin[0] - actor->v.origin[0]; deltay = enemy->v.origin[1] - actor->v.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 ( ((rand()&3) & 1) || abs(deltay)>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 (rand()&1) /*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->v.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 (!SV_CheckBottom (actor)) SV_FixCheckBottom (actor); }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean inwater; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; groundentity = PROG_TO_EDICT(ent->v.groundentity); if ((int)groundentity->v.flags & FL_CONVEYOR) VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); else VectorCopy(vec_origin, ent->v.basevelocity); //@@ pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); PF_WaterMove(); SV_CheckVelocity (ent); wasonground = (int)ent->v.flags & FL_ONGROUND; // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // add gravity except: // flying monsters // swimming monsters who are in the water inwater = SV_CheckWater(ent); if (! wasonground) if (!((int)ent->v.flags & FL_FLY)) if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0))) { if (ent->v.velocity[2] < sv_gravity.value*-0.1) hitsound = true; if (!inwater) SV_AddGravity (ent); } if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin)) { ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // apply friction // let dead monsters who aren't completely onground slide if (wasonground) if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent))) { vel = ent->v.velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction.value; control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; newspeed = speed - host_frametime*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] = vel[0] * newspeed; vel[1] = vel[1] * newspeed; } } VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); SV_FlyMove (ent, host_frametime, NULL); VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); // determine if it's on solid ground at all { vec3_t mins, maxs, point; int x, y; VectorAdd (ent->v.origin, ent->v.mins, mins); VectorAdd (ent->v.origin, ent->v.maxs, maxs); point[2] = mins[2] - 1; for (x=0 ; x<=1 ; x++) for (y=0 ; y<=1 ; y++) { point[0] = x ? maxs[0] : mins[0]; point[1] = y ? maxs[1] : mins[1]; if (SV_PointContents (point) == CONTENTS_SOLID) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; break; } } } SV_LinkEdict (ent, true); if ((int)ent->v.flags & FL_ONGROUND) if (!wasonground) if (hitsound) SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); } // regular thinking SV_RunThink (ent); SV_CheckWaterTransition (ent); }
void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist ) { float deltax, deltay; float tempdir, olddir, turnaround; vec3_t d; olddir = anglemod(((int)( actor->v.ideal_yaw / 45.0f )) * 45.0f ); turnaround = anglemod( olddir - 180 ); deltax = destination[0] - actor->v.origin[0]; deltay = destination[1] - actor->v.origin[1]; if( deltax > 10 ) d[1] = 0.0f; else if( deltax < -10 ) d[1] = 180.0f; else d[1] = -1; if( deltay < -10 ) d[2] = 270.0f; else if( deltay > 10 ) d[2] = 90.0f; else d[2] = -1; // try direct route if( d[1] != -1 && d[2] != -1 ) { if( d[1] == 0.0f ) tempdir = ( d[2] == 90.0f ) ? 45.0f : 315.0f; else tempdir = ( d[2] == 90.0f ) ? 135.0f : 215.0f; if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) return; } // try other directions if( Com_RandomLong( 0, 1 ) != 0 || fabs( deltay ) > fabs( deltax )) { tempdir = d[1]; d[1] = d[2]; d[2] = tempdir; } if( d[1] != -1 && d[1] != turnaround && SV_StepDirection( actor, d[1], dist )) return; if( d[2] != -1 && d[2] != turnaround && SV_StepDirection( actor, d[2], dist )) return; // there is no direct path to the player, so pick another direction if( olddir != -1 && SV_StepDirection( actor, olddir, dist )) return; // fine, just run somewhere. if( Com_RandomLong( 0, 1 ) != 1 ) { for( tempdir = 0; tempdir <= 315; tempdir += 45 ) { if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) return; } } else { for( tempdir = 315; tempdir >= 0; tempdir -= 45 ) { if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) return; } } // we tried. run backwards. that ought to work... if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist )) return; // well, we're stuck somehow. actor->v.ideal_yaw = olddir; // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all. if( !SV_CheckBottom( actor, MOVE_NORMAL )) { actor->v.flags |= FL_PARTIALGROUND; } }
/* ============= SV_movestep 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 ============= */ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; edict_t *enemy; // try the move VectorCopy (ent->v.origin, oldorg); VectorAdd (ent->v.origin, move, neworg); // flying monsters don't step up if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->v.origin, move, neworg); enemy = PROG_TO_EDICT(ent->v.enemy); if (i == 0 && enemy != sv.edicts) { dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; if (dz > 40) neworg[2] -= 8; if (dz < 30) neworg[2] += 8; } trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, FALSE, ent); if (trace.fraction == 1) { if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) return FALSE; // swim monster left water VectorCopy (trace.endpos, ent->v.origin); if (relink) SV_LinkEdict (ent, TRUE); return TRUE; } if (enemy == sv.edicts) break; } return FALSE; } // push down from a step height above the wished position neworg[2] += STEPSIZE; VectorCopy (neworg, end); end[2] -= STEPSIZE*2; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, FALSE, ent); if (trace.allsolid) return FALSE; if (trace.startsolid) { neworg[2] -= STEPSIZE; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, FALSE, ent); if (trace.allsolid || trace.startsolid) return FALSE; } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( (int)ent->v.flags & FL_PARTIALGROUND ) { VectorAdd (ent->v.origin, move, ent->v.origin); if (relink) SV_LinkEdict (ent, TRUE); ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // Con_Printf ("fall down\n"); return TRUE; } return FALSE; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->v.origin); if (!SV_CheckBottom (ent)) { if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) SV_LinkEdict (ent, TRUE); return TRUE; } VectorCopy (oldorg, ent->v.origin); return FALSE; } if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // Con_Printf ("back on ground\n"); ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; } ent->v.groundentity = EDICT_TO_PROG(trace.ent); // the move is ok if (relink) SV_LinkEdict (ent, TRUE); return TRUE; }
qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink ) { int i; trace_t trace; vec3_t oldorg, neworg, end; edict_t *enemy; float dz; VectorCopy( ent->v.origin, oldorg ); VectorAdd( ent->v.origin, move, neworg ); // well, try it. Flying and swimming monsters are easiest. if( ent->v.flags & ( FL_SWIM|FL_FLY )) { // try one move with vertical motion, then one without for( i = 0; i < 2; i++ ) { VectorAdd( ent->v.origin, move, neworg ); enemy = ent->v.enemy; if( i == 0 && enemy != NULL ) { dz = ent->v.origin[2] - enemy->v.origin[2]; if( dz > 40 ) neworg[2] -= 8; else if( dz < 30 ) neworg[2] += 8; } trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent ); if( trace.fraction == 1.0f ) { svs.groupmask = ent->v.groupinfo; // that move takes us out of the water. // apparently though, it's okay to travel into solids, lava, sky, etc :) if(( ent->v.flags & FL_SWIM ) && SV_PointContents( trace.endpos ) == CONTENTS_EMPTY ) return 0; VectorCopy( trace.endpos, ent->v.origin ); if( relink ) SV_LinkEdict( ent, true ); return 1; } else { if( !SV_IsValidEdict( enemy )) break; } } return 0; } else { dz = svgame.movevars.stepsize; neworg[2] += dz; VectorCopy( neworg, end ); end[2] -= dz * 2.0f; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); if( trace.allsolid ) return 0; if( trace.startsolid != 0 ) { neworg[2] -= dz; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); if( trace.allsolid != 0 || trace.startsolid != 0 ) return 0; } if( trace.fraction == 1.0f ) { if( ent->v.flags & FL_PARTIALGROUND ) { VectorAdd( ent->v.origin, move, ent->v.origin ); if( relink ) SV_LinkEdict( ent, true ); ent->v.flags &= ~FL_ONGROUND; return 1; } return 0; } else { VectorCopy( trace.endpos, ent->v.origin ); if( SV_CheckBottom( ent, MOVE_NORMAL ) == 0 ) { if( ent->v.flags & FL_PARTIALGROUND ) { if( relink ) SV_LinkEdict( ent, true ); return 1; } VectorCopy( oldorg, ent->v.origin ); return 0; } else { ent->v.flags &= ~FL_PARTIALGROUND; ent->v.groundentity = trace.ent; if( relink ) SV_LinkEdict( ent, true ); return 1; } } } }
qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink ) { float temp; vec3_t oldorg, neworg, end; trace_t trace; VectorCopy( ent->v.origin, oldorg ); VectorAdd( ent->v.origin, move, neworg ); temp = svgame.movevars.stepsize; neworg[2] += temp; VectorCopy( neworg, end ); end[2] -= temp * 2.0f; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); if( trace.allsolid != 0 ) return 0; if( trace.startsolid != 0 ) { neworg[2] -= temp; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); if( trace.allsolid != 0 || trace.startsolid != 0 ) return 0; } if( trace.fraction == 1.0f ) { if( ent->v.flags & FL_PARTIALGROUND ) { VectorAdd( ent->v.origin, move, ent->v.origin ); if( relink ) SV_LinkEdict( ent, true ); ent->v.flags &= ~FL_ONGROUND; return 1; } return 0; } else { VectorCopy( trace.endpos, ent->v.origin ); if( SV_CheckBottom( ent, MOVE_WORLDONLY ) == 0 ) { if( ent->v.flags & FL_PARTIALGROUND ) { if( relink ) SV_LinkEdict( ent, true ); return 1; } VectorCopy( oldorg, ent->v.origin ); return 0; } else { ent->v.flags &= ~FL_PARTIALGROUND; ent->v.groundentity = trace.ent; if( relink ) SV_LinkEdict( ent, true ); return 1; } } }
/* ============= SV_Physics_Step Monsters freefall when they don't have a ground entity, otherwise all movement is done with discrete steps. This is also used for objects that have become still on the ground, but will fall if the floor is pulled out from under them. ============= */ void SV_Physics_Step( edict_t *ent ) { qboolean inwater; qboolean wasonground; qboolean wasonmover; vec3_t mins, maxs; vec3_t point; trace_t trace; int x, y; SV_WaterMove( ent ); SV_CheckVelocity( ent ); wasonground = (ent->v.flags & FL_ONGROUND); wasonmover = SV_CheckMover( ent ); inwater = SV_CheckWater( ent ); if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 ) { float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime; SV_AddGravity( ent ); ent->v.velocity[2] += buoyancy; } if( !wasonground && !( ent->v.flags & FL_FLY ) && (!( ent->v.flags & FL_SWIM ) || ent->v.waterlevel <= 0 )) { if( !inwater ) SV_AddGravity( ent ); } if( !VectorIsNull( ent->v.velocity ) || !VectorIsNull( ent->v.basevelocity )) { ent->v.flags &= ~FL_ONGROUND; if(( wasonground || wasonmover ) && ( ent->v.health > 0 || SV_CheckBottom( ent, MOVE_NORMAL ))) { float *vel = ent->v.velocity; float control, speed, newspeed; float friction; speed = sqrt(( vel[0] * vel[0] ) + ( vel[1] * vel[1] )); // DotProduct2D if( speed ) { friction = sv_friction->value * ent->v.friction; // factor ent->v.friction = 1.0f; // g-cont. ??? if( wasonmover ) friction *= 0.5f; // add a little friction control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed; newspeed = speed - (host.frametime * control * friction); if( newspeed < 0 ) newspeed = 0; newspeed /= speed; vel[0] = vel[0] * newspeed; vel[1] = vel[1] * newspeed; } } VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); SV_FlyMove( ent, host.frametime, NULL ); if( ent->free ) return; SV_CheckVelocity( ent ); VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); VectorAdd( ent->v.origin, ent->v.mins, mins ); VectorAdd( ent->v.origin, ent->v.maxs, maxs ); point[2] = mins[2] - 1.0f; for( x = 0; x <= 1; x++ ) { if( ent->v.flags & FL_ONGROUND ) break; for( y = 0; y <= 1; y++ ) { point[0] = x ? maxs[0] : mins[0]; point[1] = y ? maxs[1] : mins[1]; trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent ); if( trace.startsolid ) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; ent->v.friction = 1.0f; break; } } } SV_LinkEdict( ent, true ); } else { if( svgame.globals->force_retouch != 0 ) { trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); // hentacle impact code if(( trace.fraction < 1.0f || trace.startsolid ) && SV_IsValidEdict( trace.ent )) { SV_Impact( ent, trace.ent, &trace ); if( ent->free ) return; } } } if( !SV_RunThink( ent )) return; SV_CheckWaterTransition( ent ); }
void SV_NewChaseDir2(edict_t *actor, vec3_t destination, float dist) { float deltax, deltay; float tempdir, olddir, turnaround; vec3_t d; olddir = anglemod(((int)(actor->v.ideal_yaw / 45.0)) * 45.0); //So, we're shaving down some of the precision. Ohkay. turnaround = anglemod(olddir - 180); deltax = destination[0] - actor->v.origin[0]; deltay = destination[1] - actor->v.origin[1]; if(deltax > 10) { d[1]= 0; } else if(deltax < -10) { d[1]= 180; } else { d[1] = -1; } //DI_NODIR, so in this function, -1 is a reserved 'null' like value. if(deltay < -10) { d[2] = 270; } else if(deltay > 10) { d[2] = 90; } else { d[2] = -1; } // try direct route if(d[1] != -1 && d[2] != -1) { if(d[1] == 0) { if(d[2] == 90) { tempdir = 45; } else { tempdir = 315; } } else { if(d[2] == 90) { tempdir = 135; } else { tempdir = 215; } } if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } // try other directions if(RandomLong(0, 1) != 0 || fabs(deltay) > fabs(deltax)) { //These were originally cast as int before compared. I cannot think of any compelling reason to do so. tempdir = d[1]; d[1] = d[2]; d[2] = tempdir; } if(d[1] != -1 && d[1] != turnaround && SV_StepDirection(actor, d[1], dist) != 0) { return; } if(d[2] != -1 && d[2] != turnaround && SV_StepDirection(actor, d[2], dist) != 0) { return; } /* there is no direct path to the player, so pick another direction */ if(olddir != -1 && SV_StepDirection(actor, olddir, dist) != 0) { return; } //Fine, just run somewhere. if(RandomLong(0, 1) != 0) { for(tempdir = 0; tempdir <= 315; tempdir += 45) { if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } } else { for(tempdir = 315; tempdir >= 0; tempdir -= 45) { if(tempdir != turnaround && SV_StepDirection(actor, tempdir, dist) != 0) { return; } } } //We tried. Run backwards. THAT ought to work... if(turnaround != -1 && SV_StepDirection(actor, turnaround, dist) != 0) { return; } //Well, we're stuck somehow. actor->v.ideal_yaw = olddir; // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all. if(SV_CheckBottom(actor) == 0) { SV_FixCheckBottom(actor); } }
qboolean SV_movetest(edict_t *ent, vec3_t move, qboolean relink) { float temp; vec3_t oldorg, neworg, end; trace_t trace; oldorg[0] = ent->v.origin[0]; oldorg[1] = ent->v.origin[1]; oldorg[2] = ent->v.origin[2]; neworg[0] = ent->v.origin[0] + move[0]; neworg[1] = ent->v.origin[1] + move[1]; neworg[2] = ent->v.origin[2] + move[2]; temp = cvar_sv_stepsize.value; neworg[2] += temp; end[0] = neworg[0]; end[1] = neworg[1]; end[2] = neworg[2]; end[2] -= temp*2; trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); if(trace.allsolid != 0) { return(0); } if(trace.startsolid != 0) { neworg[2] -= temp; trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); if(trace.allsolid != 0 || trace.startsolid != 0) { return(0); } } if(trace.fraction == 1) { if(ent->v.flags & FL_PARTIALGROUND) { ent->v.origin[0] += move[0]; ent->v.origin[1] += move[1]; ent->v.origin[2] += move[2]; if(relink != 0) { SV_LinkEdict(ent, 1); } ent->v.flags &= ~FL_ONGROUND; return(1); } return(0); } else { ent->v.origin[0] = trace.endpos[0]; ent->v.origin[1] = trace.endpos[1]; ent->v.origin[2] = trace.endpos[2]; if(SV_CheckBottom(ent) == 0) { if(ent->v.flags & FL_PARTIALGROUND) { if(relink != 0) { SV_LinkEdict(ent, 1); } return(1); } ent->v.origin[0] = oldorg[0]; ent->v.origin[1] = oldorg[1]; ent->v.origin[2] = oldorg[2]; return(0); } else { if(ent->v.flags & FL_PARTIALGROUND) { ent->v.flags &= ~FL_PARTIALGROUND; } ent->v.groundentity = trace.pHit; if(relink != 0) { SV_LinkEdict(ent, 1); } return(1); } } }
/* DESCRIPTION: SV_movestep/movetest // LOCATION: sv_move.c // PATH: PF_walkmove_I // // (from QW): 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 */ qboolean SV_movestep(edict_t *ent, vec3_t move, qboolean relink) { int i, var_6C_hullnum; float dz; trace_t trace; vec3_t oldorg, neworg, end; edict_t * enemy; if(ent->v.flags & FL_MONSTERCLIP) { //Don't know what one has to do with the other. var_6C_hullnum = 1; } else { var_6C_hullnum = 0; } oldorg[0] = ent->v.origin[0]; oldorg[1] = ent->v.origin[1]; oldorg[2] = ent->v.origin[2]; neworg[0] = ent->v.origin[0] + move[0]; neworg[1] = ent->v.origin[1] + move[1]; neworg[2] = ent->v.origin[2] + move[2]; //well, try it. Flying and swimming monsters are easiest. if(ent->v.flags & (FL_SWIM | FL_FLY)) { // try one move with vertical motion, then one without for(i = 0; i < 2; i++) { neworg[0] = ent->v.origin[0] + move[0]; neworg[1] = ent->v.origin[1] + move[1]; neworg[2] = ent->v.origin[2] + move[2]; enemy = ent->v.enemy; if(i == 0 && enemy != NULL) { dz = ent->v.origin[2] - enemy->v.origin[2]; if(dz > 40) { neworg[2] -= 8; } else if(dz < 30) { neworg[2] += 8; } } trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, neworg, 0, ent, var_6C_hullnum); if(trace.fraction == 1) { //yaay global_g_groupmask = ent->v.groupinfo; if((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == Q1CONTENTS_EMPTY) { return(0); //That move takes us out of the water. Apparently though, it's okay to travel into solids, lava, sky, etc :) } ent->v.origin[0] = trace.endpos[0]; ent->v.origin[1] = trace.endpos[1]; ent->v.origin[2] = trace.endpos[2]; if(relink != 0) { SV_LinkEdict(ent, 1); } return(1); } else { if(enemy == NULL) { break; } } } return(0); } else { dz = cvar_sv_stepsize.value; neworg[2] += dz; end[0] = neworg[0]; end[1] = neworg[1]; end[2] = neworg[2]; end[2] -= dz*2; trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent, var_6C_hullnum); if(trace.allsolid != 0) { return(0); } if(trace.startsolid != 0) { neworg[2] -= dz; trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, 0, ent, var_6C_hullnum); if(trace.allsolid != 0 || trace.startsolid != 0) { return(0); } } if(trace.fraction == 1) { if(ent->v.flags & FL_PARTIALGROUND) { //Whoa, where'd the ground go? ent->v.origin[0] += move[0]; ent->v.origin[1] += move[1]; ent->v.origin[2] += move[2]; if(relink != 0) { SV_LinkEdict(ent, 1); } ent->v.flags &= ~FL_ONGROUND; return(1); } return(0); //Fell off like a green koopa. } else { ent->v.origin[0] = trace.endpos[0]; ent->v.origin[1] = trace.endpos[1]; ent->v.origin[2] = trace.endpos[2]; if(SV_CheckBottom(ent) == 0) { if(ent->v.flags & FL_PARTIALGROUND) { if(relink != 0) { SV_LinkEdict(ent, 1); } return(1); } ent->v.origin[0] = oldorg[0]; ent->v.origin[1] = oldorg[1]; ent->v.origin[2] = oldorg[2]; return(0); } else { if(ent->v.flags & FL_PARTIALGROUND) { ent->v.flags &= ~FL_PARTIALGROUND; } ent->v.groundentity = trace.pHit; if(relink != 0) { SV_LinkEdict(ent, 1); } return(1); } } } }
/* ============= SV_movestep 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 ============= */ qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean set_trace) { float dz; vec3_t oldorg, neworg, end; trace_t trace; int i; edict_t *enemy; // try the move VectorCopy (ent->v.origin, oldorg); VectorAdd (ent->v.origin, move, neworg); // flying monsters don't step up, unless no_z turned on if ( ((int)ent->v.flags&(FL_SWIM|FL_FLY)) && !((int)ent->v.flags&FL_NOZ) && !((int)ent->v.flags&FL_HUNTFACE)) { // try one move with vertical motion, then one without for (i=0 ; i<2 ; i++) { VectorAdd (ent->v.origin, move, neworg); if (!noenemy) { enemy = PROG_TO_EDICT(ent->v.enemy); if (i == 0 && enemy != sv.edicts) { if((int)ent->v.flags&FL_HUNTFACE)//Go for face dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2] + PROG_TO_EDICT(ent->v.enemy)->v.view_ofs[2]; else dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; if (dz > 40) neworg[2] -= 8; else if (dz < 30) neworg[2] += 8; } } if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(neworg) == CONTENTS_EMPTY ) {//Would end up out of water, don't do z move neworg[2]=ent->v.origin[2]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); if (set_trace) set_move_trace(&trace); if(trace.fraction < 1||SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) return false; // swim monster left water } else { trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); if (set_trace) set_move_trace(&trace); } if (trace.fraction == 1) { VectorCopy (trace.endpos, ent->v.origin); if (relink) SV_LinkEdict (ent, true); return true; } if (noenemy || enemy == sv.edicts) break; } return false; } // push down from a step height above the wished position neworg[2] += STEPSIZE; VectorCopy (neworg, end); end[2] -= STEPSIZE*2; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); if (set_trace) set_move_trace(&trace); if (trace.allsolid) { return false; } if (trace.startsolid) { neworg[2] -= STEPSIZE; trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); if (set_trace) set_move_trace(&trace); if (trace.allsolid || trace.startsolid) { return false; } } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ( (int)ent->v.flags & FL_PARTIALGROUND ) { VectorAdd (ent->v.origin, move, ent->v.origin); if (relink) SV_LinkEdict (ent, true); ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // Con_Printf ("fall down\n"); return true; } return false; // walked off an edge } // check point traces down for dangling corners VectorCopy (trace.endpos, ent->v.origin); if (!SV_CheckBottom (ent)) { if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) SV_LinkEdict (ent, true); return true; } VectorCopy (oldorg, ent->v.origin); return false; } if ( (int)ent->v.flags & FL_PARTIALGROUND ) { // Con_Printf ("back on ground\n"); ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; } ent->v.groundentity = EDICT_TO_PROG(trace.ent); // the move is ok if (relink) SV_LinkEdict (ent, true); return true; }