/* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity(edict_t * ent, vec3_t push) { trace_t trace; vec3_t end; VectorAdd(ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) // only clip against bmodels trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); else trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); VectorCopy(trace.endpos, ent->v.origin); SV_LinkEdict(ent, true); if (trace.ent) SV_Impact(ent, trace.ent); return trace; }
qboolean SV_CheckBottom(edict_t * ent) { vec3_t mins, maxs, start, stop; trace_t trace; int x, y; float mid, bottom; VectorAdd(ent->v.origin, ent->v.mins, mins); VectorAdd(ent->v.origin, ent->v.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 ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; if (SV_PointContents(start) != CONTENTS_SOLID) goto realcheck; } c_yes++; return true; // we got out easy realcheck: 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.5; start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5; stop[2] = start[2] - 2 * STEPSIZE; trace = SV_Move(start, vec3_origin, vec3_origin, stop, true, ent); 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 ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; trace = SV_Move(start, vec3_origin, vec3_origin, stop, true, ent); if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) return false; } c_yes++; return true; }
/** * This function is used to decide if a bot can see his enemy or not * (this is just a recoded PF_traceline) */ bool Traceline(vec3_t start, vec3_t end, edict_t *self, edict_t *enemy) { trace_t trace = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NOMONSTERS, self); if (trace.fraction >= 0.999f) // If there were no walls { //AddTrail(start,trace.endpos,3,0.05f,1.5f,zerodir); trace = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, self); if (trace.ent == enemy) // And there were no other entities in the way return true; // Then the bot can see him } return false; // Otherwise he cant }
trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) { edict_t tempent, *tent; trace_t trace; vec3_t move, end; double save_frametime; save_frametime = host_frametime; host_frametime = 0.05; memcpy (&tempent, ent, sizeof(edict_t)); tent = &tempent; while (1) { SV_CheckVelocity (tent); SV_AddGravity (tent); VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); VectorScale (tent->v.velocity, host_frametime, move); VectorAdd (tent->v.origin, move, end); trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); VectorCopy (trace.endpos, tent->v.origin); if (trace.ent) if (trace.ent != ignore) break; } host_frametime = save_frametime; return trace; }
void TraceLineToEntity(vec3_t start, vec3_t end, vec3_t impact, edict_t *ent) { trace_t trace; memset(&trace, 0, sizeof(trace)); trace = SV_Move(start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent); VectorCopy(trace.endpos, impact); }
/* ========= Traceline This function is used to decide if a bot can see his enemy or not (this is just a recoded PF_traceline) ========= */ float BotTraceline (vec3_t start, vec3_t end, edict_t *self) { trace_t trace; trace = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, self); return trace.fraction; }
//#ifdef QUAKE2 // 2001-09-16 Quake 2 builtin functions by id/Maddes trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) { edict_t tempent, *tent; trace_t trace; vec3_t move; vec3_t end; double save_frametime; // extern particle_t *active_particles, *free_particles; // particle_t *p; int i; // 2001-09-16 SV_Trace_Toss endless loop fix by LordHavoc save_frametime = host_frametime; host_frametime = 0.05; memcpy(&tempent, ent, sizeof(edict_t)); tent = &tempent; // 2001-09-16 SV_Trace_Toss endless loop fix by LordHavoc start // while (1) for (i = 0;i < 200;i++) //sanity check; never trace more than 10 seconds // 2001-09-16 SV_Trace_Toss endless loop fix by LordHavoc end { SV_CheckVelocity (tent); SV_AddGravity (tent); VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); VectorScale (tent->v.velocity, host_frametime, move); VectorAdd (tent->v.origin, move, end); trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); VectorCopy (trace.endpos, tent->v.origin); // p = free_particles; // if (p) // { // free_particles = p->next; // p->next = active_particles; // active_particles = p; // // p->die = 256; // p->color = 15; // p->type = pt_static; // VectorCopy (vec3_origin, p->vel); // VectorCopy (tent->v.origin, p->org); // } if (trace.ent) if (trace.ent != ignore) break; } // p->color = 224; host_frametime = save_frametime; return trace; }
trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) { edict_t tempent, *tent; trace_t trace; vec3_t move; vec3_t end; double save_frametime; // extern particle_t *active_particles, *free_particles; // particle_t *p; save_frametime = host_frametime; host_frametime = 0.05; memcpy(&tempent, ent, sizeof(edict_t)); tent = &tempent; while (1) { SV_CheckVelocity (tent); SV_AddGravity (tent); VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); VectorScale (tent->v.velocity, host_frametime, move); VectorAdd (tent->v.origin, move, end); trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); VectorCopy (trace.endpos, tent->v.origin); // p = free_particles; // if (p) // { // free_particles = p->next; // p->next = active_particles; // active_particles = p; // // p->die = 256; // p->color = 15; // p->type = pt_static; // VectorCopy (vec3_origin, p->vel); // VectorCopy (tent->v.origin, p->org); // } if (trace.ent) if (trace.ent != ignore) break; } // p->color = 224; host_frametime = save_frametime; return trace; }
static void CPQW_traceline (progs_t *pr) { float *v1, *v2; edict_t *ent; int nomonsters; trace_t trace; static int tl_to_move[] = { MOVE_NORMAL, MOVE_NORMAL, MOVE_NORMAL, MOVE_TRIGGERS, MOVE_EVERYTHING, }; v1 = P_VECTOR (pr, 0); v2 = P_VECTOR (pr, 1); nomonsters = P_FLOAT (pr, 2); ent = P_EDICT (pr, 3); if (nomonsters < TL_ANY_SOLID || nomonsters > TL_EVERYTHING) nomonsters = TL_ANY_SOLID; nomonsters = tl_to_move[nomonsters]; if (sv_antilag->int_val == 2) nomonsters |= MOVE_LAGGED; trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent); *sv_globals.trace_allsolid = trace.allsolid; *sv_globals.trace_startsolid = trace.startsolid; *sv_globals.trace_fraction = trace.fraction; *sv_globals.trace_inwater = trace.inwater; *sv_globals.trace_inopen = trace.inopen; VectorCopy (trace.endpos, *sv_globals.trace_endpos); VectorCopy (trace.plane.normal, *sv_globals.trace_plane_normal); *sv_globals.trace_plane_dist = trace.plane.dist; if (trace.ent) *sv_globals.trace_ent = EDICT_TO_PROG (pr, trace.ent); else *sv_globals.trace_ent = EDICT_TO_PROG (pr, sv.edicts); }
/* ============ SV_PushEntity Does not change the entities velocity at all ============ */ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int *blocked ) { trace_t trace; int type; vec3_t end; VectorAdd( ent->v.origin, lpush, end ); if( ent->v.movetype == MOVETYPE_FLYMISSILE ) type = MOVE_MISSILE; else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT ) type = MOVE_NOMONSTERS; // only clip against bmodels else type = MOVE_NORMAL; trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent ); if( trace.fraction != 0.0f ) { VectorCopy( trace.endpos, ent->v.origin ); if( sv.state == ss_active && apush[YAW] && ( ent->v.flags & FL_CLIENT )) { ent->v.avelocity[1] += apush[1]; ent->v.fixangle = 2; } // don't rotate pushables! if( SV_AllowPushRotate( ent )) ent->v.angles[YAW] += trace.fraction * apush[YAW]; } SV_LinkEdict( ent, true ); if( blocked ) *blocked = !VectorCompare( ent->v.origin, end ); // can't move full distance // so we can run impact function afterwards. if( SV_IsValidEdict( trace.ent )) SV_Impact( ent, trace.ent, &trace ); return trace; }
/* ================== SV_UserFriction ================== */ void SV_UserFriction (void) { float *vel; float speed, newspeed, control; vec3_t start, stop; float friction; trace_t trace; vel = velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (!speed) return; // if the leading edge is over a dropoff, increase friction start[0] = stop[0] = origin[0] + vel[0]/speed*16; start[1] = stop[1] = origin[1] + vel[1]/speed*16; start[2] = origin[2] + sv_player->v.mins[2]; stop[2] = start[2] - 34; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player); if (trace.fraction == 1.0) friction = sv_friction.value*sv_edgefriction.value; else friction = sv_friction.value; // apply 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; vel[2] = vel[2] * newspeed; }
void Physics_AddFriction(edict_t *eEntity,vec3_t vVelocity,vec3_t vOrigin) { float *vel; float speed, newspeed, control; vec3_t start, stop; float friction; trace_t trace; vel = vVelocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if(!speed) return; // If the leading edge is over a dropoff, increase friction start[0] = stop[0] = vOrigin[0] + vel[0]/speed*16.0f; start[1] = stop[1] = vOrigin[1] + vel[1]/speed*16.0f; start[2] = vOrigin[2] + eEntity->v.mins[2]; stop[2] = start[2] - 34; trace = SV_Move(start,mv3Origin,mv3Origin,stop,true,eEntity); if(trace.fraction == 1.0f) friction = eEntity->Physics.fFriction*sv_edgefriction.value; else friction = eEntity->Physics.fFriction; // Apply friction control = speed < cvPhysicsStopSpeed.value ? cvPhysicsStopSpeed.value : speed; newspeed = speed - host_frametime*control*friction; if(newspeed < 0) newspeed = 0; newspeed /= speed; Math_VectorScale(vel,newspeed,vel); }
/* DESCRIPTION: SV_Trace_Toss // LOCATION: sv_phys.c // PATH: PF_TraceToss_Shared // // Say I throw a grenade. Where will it go? This function finds out by // simulating ten seconds' worth of frames. */ trace_t * SV_Trace_Toss(trace_t * Outgoing_Trace, edict_t *tossent, edict_t *ignore) { int i; vec3_t var_378_end; vec3_t var_36C_move; trace_t var_360_trace; edict_t var_324_TempEdict; edict_t * var_328_TempEdictPtr; double var_380_host_frametime; var_380_host_frametime = host_frametime; host_frametime = .05; Q_memcpy(&var_324_TempEdict, tossent, sizeof(edict_t)); var_328_TempEdictPtr = &var_324_TempEdict; // while(1) //a sanity check to avoid tracing more than ten seconds was present in QW, I think it's a good idea. This may need to be adjusted to account for the alterable frametimes. for (i = 0; i < 200; i++) { SV_CheckVelocity(var_328_TempEdictPtr); SV_AddGravity(var_328_TempEdictPtr); VectorMA(var_328_TempEdictPtr->v.angles, host_frametime, var_328_TempEdictPtr->v.avelocity, var_328_TempEdictPtr->v.angles); VectorScale(var_328_TempEdictPtr->v.velocity, host_frametime, var_36C_move); VectorAdd(var_328_TempEdictPtr->v.origin, var_36C_move, var_378_end); var_360_trace = SV_Move(var_328_TempEdictPtr->v.origin, var_328_TempEdictPtr->v.mins, var_328_TempEdictPtr->v.maxs, var_378_end, 0, var_328_TempEdictPtr, 0); VectorCopy(var_360_trace.endpos, var_328_TempEdictPtr->v.origin); if(var_360_trace.pHit != NULL && var_360_trace.pHit != ignore) { break; } } host_frametime = var_380_host_frametime; Q_memcpy(Outgoing_Trace, &var_360_trace, sizeof(trace_t)); return(Outgoing_Trace); }
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; } } }
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; } } } }
void SV_SetIdealPitch (void) { float angleval, sinval, cosval; trace_t tr; vec3_t top, bottom; float z[MAX_FORWARD]; int i, j; int step, dir, steps; if (!((int)sv_player->v.flags & FL_ONGROUND)) return; angleval = sv_player->v.angles[YAW] * M_PI*2 / 360; sinval = sin(angleval); cosval = cos(angleval); for (i=0 ; i<MAX_FORWARD ; i++) { top[0] = sv_player->v.origin[0] + cosval*(i+3)*12; top[1] = sv_player->v.origin[1] + sinval*(i+3)*12; top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2]; bottom[0] = top[0]; bottom[1] = top[1]; bottom[2] = top[2] - 160; tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player); if (tr.allsolid) return; // looking at a wall, leave ideal the way is was if (tr.fraction == 1) return; // near a dropoff z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); } dir = 0; steps = 0; for (j=1 ; j<i ; j++) { step = z[j] - z[j-1]; if (step > -ON_EPSILON && step < ON_EPSILON) continue; if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) return; // mixed changes steps++; dir = step; } if (!dir) { sv_player->v.idealpitch = 0; return; } if (steps < 2) return; sv_player->v.idealpitch = -dir * sv_idealpitchscale.value; }
int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; Math_VectorCopy (ent->v.velocity, original_velocity); Math_VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; for (i=0 ; i<3 ; i++) end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, FALSE, ent); if(trace.bAllSolid) { // Entity is trapped in another solid Math_VectorCopy(mv3Origin, ent->v.velocity); return 3; } if (trace.fraction > 0) { // Actually covered some distance Math_VectorCopy (trace.endpos, ent->v.origin); Math_VectorCopy (ent->v.velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance if(!trace.ent) { Sys_Error ("SV_FlyMove: !trace.ent"); return 0; } if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if (trace.ent->Physics.iSolid == SOLID_BSP) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } if (!trace.plane.normal[2]) { blocked |= 2; // step if (steptrace) *steptrace = trace; // save for player extrafriction } // Run the impact function Physics_Impact(ent,trace.ent); if (ent->free) break; // removed by the impact function time_left -= time_left * trace.fraction; // Cliped to another plane if(numplanes >= MAX_CLIP_PLANES) { // This shouldn't really happen Math_VectorCopy(mv3Origin, ent->v.velocity); return 3; } Math_VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // Modify original_velocity so it parallels all of the clip planes for(i = 0; i < numplanes; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if(Math_DotProduct(new_velocity,planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) Math_VectorCopy (new_velocity, ent->v.velocity); else { // Go along the crease if (numplanes != 2) { Math_VectorCopy(mv3Origin, ent->v.velocity); return 7; } Math_CrossProduct(planes[0], planes[1], dir); d = Math_DotProduct(dir, ent->v.velocity); Math_VectorScale(dir, d, ent->v.velocity); } // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners if(Math_DotProduct(ent->v.velocity,primal_velocity) <= 0) { Math_VectorCopy(mv3Origin,ent->v.velocity); return blocked; } } return blocked; }
qboolean SV_CheckBottom (edict_t *ent) {//By this point, ent has been moved to it's new position after the //move, and adjusted for steps vec3_t mins, maxs, start, stop; trace_t trace; int x, y; float mid, bottom; float save_hull; VectorAdd (ent->v.origin, ent->v.mins, mins); VectorAdd (ent->v.origin, ent->v.maxs, maxs); /*//Make it use the clipping hull's size, not their bounding box... model = sv.models[ (int)sv.edicts->v.modelindex ]; VectorSubtract (ent->v.maxs, ent->v.mins, size); if(ent->v.hull) { index = ent->v.hull-1; wclip_hull = &model->hulls[index];; if (!wclip_hull) // Invalid hull { Con_Printf ("ERROR: hull %d is null.\n",wclip_hull); wclip_hull = &model->hulls[0]; } } else // Using the old way uses size to determine hull to use { if (size[0] < 3) // Point wclip_hull = &model->hulls[0]; else if (size[0] <= 8) // Pentacles wclip_hull = &model->hulls[4]; else if (size[0] <= 32 && size[2] <= 28) // Half Player wclip_hull = &model->hulls[3]; else if (size[0] <= 32) // Full Player wclip_hull = &model->hulls[1]; else // Golumn wclip_hull = &model->hulls[5]; } VectorAdd (ent->v.origin, wclip_hull->clip_mins, mins); VectorAdd (ent->v.origin, wclip_hull->clip_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<2 ; x++) for (y=0 ; y<2 ; y++) { if(x) start[0] = maxs[0]; else start[0] = mins[0]; if(y) start[1] = maxs[1]; else start[1] = mins[1]; // start[0] = x ? maxs[0] : mins[0]; // start[1] = y ? maxs[1] : mins[1]; if (SV_PointContents (start) != CONTENTS_SOLID) goto realcheck; } // c_yes++; return true; // we got out easy realcheck: // check it for real... // c_no++; start[2] = mins[2]; // the midpoint must be within 16 of the bottom start[0] = stop[0] = (mins[0] + maxs[0])*0.5; start[1] = stop[1] = (mins[1] + maxs[1])*0.5; stop[2] = start[2] - 2*STEPSIZE; //do a trace from the bottom center of the ent down //to 36 below the bottom center of the ent, using a point hull //the "true" in this function is telling SV_Move to consider //this ent's movement as MOVE_NOMONSTERS - means it will //not clip against entities in this move //NOTE: these don't check for trace_allsolid of trace_startsolid. //Technically, these can't possibly be a valid result since //the start point is in the ent, but what about imprecision? save_hull = ent->v.hull;//temp hack so it HullForEntity doesn't calculate the wrong offset ent->v.hull = 0; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); ent->v.hull = save_hull; /* if((int)ent->v.flags&FL_MONSTER) { if(trace.allsolid) Con_DPrintf("Checkbottom midpoint check was all solid!!!\n"); else if(trace.startsolid) Con_DPrintf("Checkbottom midpoint check started solid!!!\n"); } */ if (trace.fraction == 1.0) return false; //trace did not reach full 36 below, so set mid and bottom //to whatever distance it did get to below the ent's //bottom centerpoint (start[2]) mid = bottom = trace.endpos[2]; // the corners must be within 16 of the midpoint for (x=0 ; x<2 ; x++) for (y=0 ; y<2 ; y++) {//check 4 corners, in this order: //x = 0, y = 0 (NE) //x = 0, y = 1 (SE) //x = 1, y = 0 (NW) //x = 1, y = 1 (SW) if(x) start[0] = stop[0] = maxs[0]; else start[0] = stop[0] = mins[0]; if(y) start[1] = stop[1] = maxs[1]; else start[1] = stop[1] = mins[1]; // start[0] = stop[0] = x ? maxs[0] : mins[0]; // start[1] = stop[1] = y ? maxs[1] : mins[1]; //same check as above, just from the 4 corners down 36 save_hull = ent->v.hull;//temp hack so it HullForEntity doesn't calculate the wrong offset ent->v.hull = 0; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); ent->v.hull = save_hull; /* if((int)ent->v.flags&FL_MONSTER) { if(trace.allsolid) Con_DPrintf("Checkbottom (x=%d,y=%d) check was all solid!!!\n",x,y); else if(trace.startsolid) Con_DPrintf("Checkbottom (x=%d,y=%d) check started solid!!!\n",x,y); }*/ //Hit a closer surface than did when checked center, //so set the "bottom" to the new, closer z height //we hit if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; //one of the corners does not have a surface within //36 below it, or the surface it did hit is more than //54 below this corner. This is a really stupid check, //because if it hits a surface more than 54 below the //ent,the trace_fraction will be 1 if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) return false; } // c_yes++; return true; }
/* ============ SV_PushEntity Does not change the entity's velocity at all ============ */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { trace_t trace; vec3_t end; int movetype; VectorAdd (ent->v.origin, push, end); if (ent->v.movetype == MOVETYPE_FLYMISSILE) movetype = MOVE_MISSILE; #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)) movetype = MOVE_MISSILE; #endif else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) movetype = MOVE_NOMONSTERS; // only clip against bmodels #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_SWIM)) movetype = MOVE_WATER; #endif else movetype = MOVE_NORMAL; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, movetype, ent); #ifdef HEXEN2_SUPPORT if (hexen2) { if (ent->v.solid != SOLID_PHASE) { if ((ent->v.movetype == MOVETYPE_BOUNCE) && !(trace.allsolid == 0 && trace.startsolid == 0)) { trace.fraction = 0; return trace; } } else // Entity is PHASED so bounce off walls and other entities, go through monsters and players { if (trace.ent) { // Go through MONSTERS and PLAYERS, can't use FL_CLIENT cause rotating brushes do if (((int) trace.ent->v.flags & FL_MONSTER) || (trace.ent->v.movetype == MOVETYPE_WALK)) { vec3_t impact; edict_t *impact_e; VectorCopy (trace.endpos, impact); impact_e = trace.ent; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_PHASE, ent); VectorCopy (impact, ent->v.origin); SV_Impact (ent, impact_e); } } } } #endif VectorCopy (trace.endpos, ent->v.origin); #ifdef _DEBUG if (!VectorCompare(trace.endpos, end)) movetype *= 1; #endif SV_LinkEdict (ent, true); if (trace.ent) SV_Impact (ent, trace.ent); return trace; }
/* ============ SV_FlyMove The basic solid body movement clip that slides along multiple planes *steptrace - if not NULL, the trace results of any vertical wall hit will be stored Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop ============ */ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) { int i, j, numplanes, bumpcount, blocked; vec3_t dir, end, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; float d, time_left, allFraction; trace_t trace; blocked = 0; VectorCopy( ent->v.velocity, original_velocity ); VectorCopy( ent->v.velocity, primal_velocity ); numplanes = 0; allFraction = 0.0f; time_left = time; for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++ ) { if( VectorIsNull( ent->v.velocity )) break; VectorMA( ent->v.origin, time_left, ent->v.velocity, end ); trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); allFraction += trace.fraction; if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.velocity ); return 4; } if( trace.fraction > 0.0f ) { // actually covered some distance VectorCopy( trace.endpos, ent->v.origin ); VectorCopy( ent->v.velocity, original_velocity ); numplanes = 0; } if( trace.fraction == 1.0f ) break; // moved the entire distance if( !trace.ent ) MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" ); if( trace.plane.normal[2] > 0.7f ) { blocked |= 1; // floor if( trace.ent->v.solid == SOLID_BSP || trace.ent->v.solid == SOLID_SLIDEBOX || trace.ent->v.movetype == MOVETYPE_PUSHSTEP || (trace.ent->v.flags & FL_CLIENT)) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; } } if( trace.plane.normal[2] == 0.0f ) { blocked |= 2; // step if( steptrace ) *steptrace = trace; // save for player extrafriction } // run the impact function SV_Impact( ent, trace.ent, &trace ); // break if removed by the impact function if( ent->free ) break; time_left -= time_left * trace.fraction; // clipped to another plane if( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen VectorClear( ent->v.velocity ); break; } VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // modify original_velocity so it parallels all of the clip planes for( i = 0; i < numplanes; i++ ) { SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f ); for( j = 0; j < numplanes; j++ ) { if( j != i ) { if( DotProduct( new_velocity, planes[j] ) < 0.0f ) break; // not ok } } if( j == numplanes ) break; } if( i != numplanes ) { // go along this plane VectorCopy( new_velocity, ent->v.velocity ); } else { // go along the crease if( numplanes != 2 ) { VectorClear( ent->v.velocity ); break; } CrossProduct( planes[0], planes[1], dir ); d = DotProduct( dir, ent->v.velocity ); VectorScale( dir, d, ent->v.velocity ); } // if current velocity is against the original velocity, // stop dead to avoid tiny occilations in sloping corners if( DotProduct( ent->v.velocity, primal_velocity ) <= 0.0f ) { VectorClear( ent->v.velocity ); break; } } if( allFraction == 0.0f ) VectorClear( ent->v.velocity ); return blocked; }
/* ============= SV_CheckBottom Returns false if any part of the bottom of the entity is off an edge that is not a staircase. ============= */ qboolean SV_CheckBottom (edict_t *ent) { vec3_t mins, maxs, start, stop; trace_t trace; int x, y; float mid, bottom; float save_hull; VectorAdd (ent->v.origin, ent->v.mins, mins); VectorAdd (ent->v.origin, ent->v.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 < 2; x++) { for (y = 0; y < 2; y++) { start[0] = x ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; if (SV_PointContents (start) != CONTENTS_SOLID) goto realcheck; } } return true; // we got out easy realcheck: // 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.5; start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5; stop[2] = start[2] - 2*STEPSIZE; save_hull = ent->v.hull;//temp hack so it HullForEntity doesn't calculate the wrong offset ent->v.hull = 0; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); ent->v.hull = save_hull; 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 < 2; x++) { for (y = 0; y < 2; y++) { start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; save_hull = ent->v.hull;//temp hack so it HullForEntity doesn't calculate the wrong offset ent->v.hull = 0; trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); ent->v.hull = save_hull; if (trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) return false; } } return true; }
/* ============= 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 ============= */ bool Server::move_step(edict_t *ent, vec3_t move, bool 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 = m_progs->prog_to_edict(ent->v.enemy); if (i == 0 && enemy != m_progs->m_edicts[0]) { dz = ent->v.origin[2] - m_progs->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) && point_contents(trace.endpos) == CONTENTS_EMPTY) return false; // swim monster left water VectorCopy(trace.endpos, ent->v.origin); if (relink) link_edict(ent, true); return true; } if (enemy == m_progs->m_edicts[0]) 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) link_edict(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 (!check_bottom(ent)) { if ((int)ent->v.flags & FL_PARTIALGROUND) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) link_edict(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 = m_progs->edict_to_prog(trace.ent); // the move is ok if (relink) link_edict(ent, true); return true; }
/* 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_CheckBottom Returns false if any part of the bottom of the entity is off an edge that is not a staircase. ============= */ qboolean SV_CheckBottom( edict_t *ent, int iMode ) { vec3_t mins, maxs, start, stop; float mid, bottom; trace_t trace; int x, y; VectorAdd( ent->v.origin, ent->v.mins, mins ); VectorAdd( ent->v.origin, ent->v.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 ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; svs.groupmask = ent->v.groupinfo; if( SV_PointContents( start ) != CONTENTS_SOLID ) goto realcheck; } } return true; // we got out easy realcheck: // check it for real... start[2] = mins[2] + svgame.movevars.stepsize; // 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 * svgame.movevars.stepsize; if( iMode == WALKMOVE_WORLDONLY ) trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent ); else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent ); if( trace.fraction == 1.0f ) 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 ? maxs[0] : mins[0]; start[1] = stop[1] = y ? maxs[1] : mins[1]; if( iMode == WALKMOVE_WORLDONLY ) trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent ); else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent ); if( trace.fraction != 1.0f && trace.endpos[2] > bottom ) bottom = trace.endpos[2]; if( trace.fraction == 1.0f || mid - trace.endpos[2] > svgame.movevars.stepsize ) return false; } } return true; }
/** * Called by bots 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 */ bool bot_movestep(edict_t *ent, vec3_t move) { // float dz; vec3_t oldorg, neworg, end; trace_t trace; // int i; // edict_t *enemy; // try the move //get the bots org VectorCopy(ent->v.origin, oldorg); //work out new position VectorAdd(ent->v.origin, move, neworg); // push down from a step height above the wished position to a step below neworg[2] += sv_stepheight.getFloat(); VectorCopy(neworg, end); end[2] -= sv_stepheight.getFloat()*2; //trace down to check if there was a floor trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); if (trace.allsolid) { //inside a wall? //Con_Printf("Trace all solid...\n"); return false; } if (trace.startsolid) { //start inside a wall? neworg[2] -= sv_stepheight.getFloat(); trace = SV_Move(neworg, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); if (trace.allsolid || trace.startsolid) { //Con_Printf("Trace start solid...\n"); return false; } } if (trace.fraction == 1) { // if monster had the ground pulled out, go ahead and fall if ((int) ent->v.flags & FL_PARTIALGROUND) { // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // Con_Printf ("fall down\n"); return true; } //Con_Printf("Walked off edge...\n"); 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 return true; } //VectorCopy (oldorg, ent->v.origin); Con_Printf("No floor?...\n"); 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 return true; }
/* ============= 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; }
/* ============= 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; }
int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->v.velocity, original_velocity); VectorCopy (ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; for (i=0 ; i<3 ; i++) end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->v.velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->v.origin); VectorCopy (ent->v.velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance if (!trace.ent) Sys_Error ("SV_FlyMove: !trace.ent"); if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if (trace.ent->v.solid == SOLID_BSP) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = ((int)EDICT_TO_PROG(trace.ent)); } } if (!trace.plane.normal[2]) { blocked |= 2; // step if (steptrace) *steptrace = trace; // save for player extrafriction } // // run the impact function // SV_Impact (ent, trace.ent); if (ent->free) break; // removed by the impact function time_left -= time_left * trace.fraction; // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorCopy (vec3_origin, ent->v.velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->v.velocity); } else { // go along the crease if (numplanes != 2) { // Con_Printf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->v.velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->v.velocity); VectorScale (dir, d, ent->v.velocity); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->v.velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->v.velocity); return blocked; } } return blocked; }
/* ============= 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 ); }