/* ============= 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. FIXME: is this true? ============= */ void SV_Physics_Step (edict_t *ent) { qbool hitsound; // frefall if not onground if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) { if (ent->v.velocity[2] < sv.movevars.gravity*-0.1) hitsound = true; else hitsound = false; SV_AddGravity (ent, 1.0); SV_CheckVelocity (ent); // Tonik: the check for SOLID_NOT is to fix the way dead bodies and // gibs behave (should not be blocked by players & monsters); // The SOLID_TRIGGER check is disabled lest we break frikbots if (ent->v.solid == SOLID_NOT /* || ent->v.solid == SOLID_TRIGGER*/) SV_FlyMove (ent, sv_frametime, NULL, MOVE_NOMONSTERS); else SV_FlyMove (ent, sv_frametime, NULL, MOVE_NORMAL); SV_LinkEdict (ent, true); if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground { if (hitsound) SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1, NULL); } } // regular thinking SV_RunThink (ent); SV_CheckWaterTransition (ent); }
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 SV_Physics_Step (edict_t *ent) { qboolean hitsound; // freefall if not onground if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) { if (ent->v.velocity[2] < sv_gravity.value*-0.1) hitsound = true; else hitsound = false; SV_AddGravity (ent); SV_CheckVelocity (ent); SV_FlyMove (ent, host_frametime, NULL); SV_LinkEdict (ent, true); if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground { if (hitsound) SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); } } // regular thinking SV_RunThink (ent); SV_CheckWaterTransition (ent); }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ TM_CALLABLE void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; // regular thinking if (!SV_RunThink (ent)) return; if (ent->v.velocity[2] > 0) ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; // if onground, return without moving if ( ((int)ent->v.flags & FL_ONGROUND) ) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent, 1.0); // move angles VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); // move origin VectorScale (ent->v.velocity, host_frametime, move); trace = SV_PushEntity (ent, move); if (trace.fraction == 1) return; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE ) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); VectorCopy (vec3_origin, ent->v.velocity); VectorCopy (vec3_origin, ent->v.avelocity); } } // check for in water SV_CheckWaterTransition (ent); }
//#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; }
/* ============= 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 hitsound; char *snd; // freefall if not onground if (!((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) { if (ent->v.velocity[2] < sv_gravity.value*-0.1) hitsound = true; else hitsound = false; SV_AddGravity (ent); SV_CheckVelocity (ent); SV_FlyMove (ent, host_frametime, NULL); SV_LinkEdict (ent, true); if ((int)ent->v.flags & FL_ONGROUND) // just hit ground #ifdef HEXEN2_SUPPORT if (!hexen2 || (!ent->v.flags & FL_MONSTER)) #endif { if (hitsound) { #ifdef HEXEN2_SUPPORT if (hexen2) snd = "fx/thngland.wav"; else #endif snd = "demon/dland2.wav"; SV_StartSound (ent, 0, snd, 255, 1); } } } // regular thinking SV_RunThink (ent); SV_CheckWaterTransition (ent); }
/* 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); }
/* ============= SV_Physics_NewToss Toss, bounce, and fly movement. When on ground and no velocity, do nothing. With velocity, slide. ============= */ void SV_Physics_NewToss (edict_t *ent) { trace_t trace; vec3_t move; // float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; qboolean wasonground; float speed, newspeed; vec3_t old_origin; // float firstmove; // int mask; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->groundentity) wasonground = true; else wasonground = false; wasinwater = ent->waterlevel; // find out what we're sitting on. VectorCopy (ent->s.origin, move); move[2] -= 0.25; trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, move, ent, ent->clipmask); if(ent->groundentity && ent->groundentity->inuse) ent->groundentity = trace.ent; else ent->groundentity = NULL; // if we're sitting on something flat and have no velocity of our own, return. if (ent->groundentity && (trace.plane.normal[2] == 1.0) && !ent->velocity[0] && !ent->velocity[1] && !ent->velocity[2]) { return; } // store the old origin VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity SV_AddGravity (ent); if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add friction speed = VectorLength(ent->velocity); if(ent->waterlevel) // friction for water movement { newspeed = speed - (sv_waterfriction * 6 * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; VectorScale (ent->velocity, newspeed, ent->velocity); } else if (!ent->groundentity) // friction for air movement { newspeed = speed - ((sv_friction)); if (newspeed < 0) newspeed = 0; newspeed /= speed; VectorScale (ent->velocity, newspeed, ent->velocity); } else // use ground friction { newspeed = speed - (sv_friction * 6); if (newspeed < 0) newspeed = 0; newspeed /= speed; VectorScale (ent->velocity, newspeed, ent->velocity); } SV_FlyMove (ent, FRAMETIME, ent->clipmask); gi.linkentity (ent); G_TouchTriggers (ent); // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if ( ent->groundentity && ent->movetype != MOVETYPE_TOSS_SLIDE ) { // JOSEPH 7-OCT-98 if (ent->fallerflag) { // JOSEPH 22-JAN-99 // If the object just hit the floor if (ent->fallingflag) { ent->fallingflag = 0; if (!strcmp(ent->classname, "props_trashcanA")) { gi.sound (ent, CHAN_AUTO, gi.soundindex ("world/trash2.wav"), 1, ATTN_NORM, 0); } else if (!strcmp(ent->classname, "props_crate")) { gi.sound (ent, CHAN_AUTO, gi.soundindex ("world/crate2.wav"), 1, ATTN_NORM, 0); } } // END JOSEPH // Fix if sitting off center ent->movetype = MOVETYPE_STEP; think_checkedges(ent); } // END JOSEPH return; } VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1) { // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) backoff = 2.0; // RAFAEL ( else ) else if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; // Ridah, testing else if (ent->velocity[2] > -120) backoff = 1; else backoff = 1.3; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) vectoangles (ent->velocity, ent->s.angles); // stop if on ground // RAFAEL if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE && ent->movetype != MOVETYPE_TOSS_SLIDE) // Ridah, testing { if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // Ridah, testing if (trace.plane.normal[2] > 0.0 && ent->movetype == MOVETYPE_TOSS_SLIDE) // Ridah, testing { VectorMA( ent->velocity, -0.07, ent->velocity, ent->velocity ); // add some friction ent->velocity[2] += ent->gravity * sv_gravity->value * FRAMETIME * trace.plane.normal[2]; if (trace.fraction <= 0.1) { float oldpitch; oldpitch = ent->s.angles[PITCH]; vectoangles (ent->velocity, ent->s.angles); ent->s.angles[PITCH] = oldpitch; VectorCopy (vec3_origin, ent->avelocity); ent->avelocity[PITCH] = -300 * VectorLength(ent->velocity)/800; // roll in direction we're going SV_Physics_Toss(ent); return; } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; // JOSEPH 13-MAY-99 /*if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);*/ // END JOSEPH // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; int retval; vec3_t oldpos; // BEGIN: Xatrix/Ridah vec3_t old_vel; // END: Xatrix/Ridah // Joseph if (ent->fallerflag) { // Fix if sitting off center think_checkedges(ent); } // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; // Ridah, 1-may-99, disabled this to prevent guys getting stuck in water // if (ent->waterlevel == 0) SV_AddGravity (ent); } /* // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } */ // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } // BEGIN: Xatrix/Ridah // JOSEPH 26-APR-99 if ((ent->svflags & SVF_MONSTER) || (ent->monsterprop)) // END JOSEPH { // if (ent->cast_info.aiflags & AI_PLAYERCLIP) mask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP; // else // mask = MASK_MONSTERSOLID; } else mask = MASK_SOLID; VectorCopy (ent->velocity, old_vel); // END: Xatrix/Ridah VectorCopy (ent->s.origin, oldpos ); retval = SV_FlyMove (ent, FRAMETIME, mask); #if 0 // leave this here for now. // Ridah, HACK... sometimes they get stuck, we should debug this properly when we get the time if (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { // move back to old position and clear velocity int iter=0; VectorCopy (oldpos, ent->s.origin); VectorClear (ent->velocity); // find a good position while (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID )) { VectorAdd( ent->s.origin, tv((random()-0.5) * 64, (random()-0.5) * 64, (random()-0.5) * 64), ent->s.origin ); if (++iter > 10) break; } // if (iter <= 4) // { // make sure they're on the ground // M_droptofloor( ent ); // } goto exit_vel_check; // get out of here? } #endif // BEGIN: Xatrix/Ridah if (!ent->groundentity || (ent->flags & FL_FLY)) { node_t *land_node; // Ridah, prevent guys getting stuck trying to jump if (VectorDistance( ent->s.origin, oldpos ) < 1 && !ent->groundentity && (ent->last_onground < (level.time - 2))) { ent->velocity[0] = crandom() * 300; ent->velocity[1] = crandom() * 300; if (ent->velocity[2] < -200) ent->velocity[2] = -200; ent->velocity[2] += random() * 350; ent->nav_data.goal_index = 0; ent->last_onground = level.time; } if (ent->velocity[2] > 80 && retval != 20) { // while rising, maintain XY velocity ent->velocity[0] = old_vel[0]; ent->velocity[1] = old_vel[1]; } // see if we've gone passed the landing position if ( !(ent->flags & FL_FLY) && (retval == -1) && (ent->nav_data.goal_index) && (land_node = level.node_data->nodes[ent->nav_data.goal_index-1])) // && (land_node->node_type & NODE_LANDING)) { vec3_t unit_vel, goal_dir, goal_vec; float vel_scale, dist; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); goal_vec[2] = 0; dist = VectorNormalize2( goal_vec, goal_dir ); if (dist > 16) { VectorCopy( ent->velocity, unit_vel ); unit_vel[2] = 0; vel_scale = VectorNormalize( unit_vel ); if (DotProduct( unit_vel, goal_dir ) < 0.8) { // we've either gone passed, or need some correction vec3_t new_pos; float old_z; if (VectorLength( goal_vec ) < 40) { new_pos[0] = land_node->origin[0]; new_pos[1] = land_node->origin[1]; new_pos[2] = ent->s.origin[2]; if (ValidBoxAtLoc( new_pos, ent->mins, ent->maxs, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID )) { // move there, it's safe, and clear velocity VectorCopy( new_pos, ent->s.origin ); ent->velocity[0] = ent->velocity[1] = 0; goto exit_vel_check; } } // we need to adjust our velocity if (land_node->origin[2] < (ent->s.origin[2] - 64)) { old_z = ent->velocity[2]; VectorScale( goal_dir, vel_scale, ent->velocity ); ent->velocity[2] = old_z; } } } } if ( (ent->flags & FL_FLY) && ((land_node = level.node_data->nodes[ent->nav_data.goal_index-1]) || ((ent->flags &= ~FL_FLY) && false)) /*&& (land_node->node_type & NODE_LANDING)*/) { // if climbing ladder, and we're reached the landing position, stop // Ridah, 8-jun-99, make sure dog's don't climb ladders if (!ent->gender) { goto abort_climb; } if (ent->s.origin[2] > land_node->origin[2]) { //gi.dprintf( "-> end of climb\n" ); // VectorSubtract( land_node->origin, ent->s.origin, ent->velocity ); AngleVectors( ent->s.angles, ent->velocity, NULL, NULL ); ent->velocity[2] = 0; VectorNormalize( ent->velocity ); VectorScale( ent->velocity, 96, ent->velocity ); ent->velocity[2] = 200; ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; // look for a new node ent->nav_data.cache_node = -1; if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else { trace_t tr; vec3_t end, goal_vec; VectorSubtract( land_node->origin, ent->s.origin, goal_vec ); ent->velocity[0] = goal_vec[0]; ent->velocity[1] = goal_vec[1]; ent->velocity[2] = 120; // if another character is above us, abort VectorCopy( ent->s.origin, end ); end[2] += 128; tr = gi.trace( ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID ); if ((tr.fraction < 1) && (tr.ent->svflags & SVF_MONSTER)) { abort_climb: AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorScale( goal_vec, -64, ent->velocity ); ent->flags &= ~FL_FLY; ent->nav_data.goal_index = 0; if (ent->cast_info.move_end_climb) { ent->cast_info.currentmove = ent->cast_info.move_end_climb; } else if (ent->cast_info.move_jump) { ent->cast_info.currentmove = ent->cast_info.move_jump; } } else if (ent->s.origin[2] > (land_node->origin[2] - 48)) { // we're near the top, stopping climbing anim //gi.dprintf( "near end of climb\n" ); if (ent->cast_info.move_end_climb) ent->cast_info.currentmove = ent->cast_info.move_end_climb; // add some forward momentum AngleVectors( ent->s.angles, goal_vec, NULL, NULL ); VectorMA( ent->velocity, 64, goal_vec, ent->velocity ); } } } } exit_vel_check: // END: Xatrix/Ridah gi.linkentity (ent); G_TouchTriggers (ent); // Note to Ryan: we can't use this because we are playing specific sounds elsewhere /* if (ent->groundentity) if (!wasonground) if (hitsound) // BEGIN: Xatrix/Ridah/Navigator/03-apr-1998 if (!(ent->cast_info.move_run)) // END: Xatrix/Ridah/Navigator/03-apr-1998 gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); */ } // regular thinking SV_RunThink (ent); }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; if (!ent) { return; } /* airborn monsters should always check for ground */ if (!ent->groundentity) { M_CheckGround(ent); } groundentity = ent->groundentity; SV_CheckVelocity(ent); if (groundentity) { wasonground = true; } else { wasonground = false; } if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) { SV_AddRotationalFriction(ent); } /* add gravity except: - flying monsters - swimming monsters who are in the water */ if (!wasonground) { if (!(ent->flags & FL_FLY)) { if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value * -0.1) { hitsound = true; } if (ent->waterlevel == 0) { SV_AddGravity(ent); } } } } /* friction for flying monsters that have been given vertical velocity */ if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction / 3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent->velocity[2] *= newspeed; } /* friction for flying monsters that have been given vertical velocity */ if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) { newspeed = 0; } newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { /* let dead monsters who aren't completely onground slide */ if ((wasonground) || (ent->flags & (FL_SWIM | FL_FLY))) { if (!((ent->health <= 0.0) && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME * control * friction; if (newspeed < 0) { newspeed = 0; } newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } } if (ent->svflags & SVF_MONSTER) { mask = MASK_MONSTERSOLID; } else { mask = MASK_SOLID; } SV_FlyMove(ent, FRAMETIME, mask); gi.linkentity(ent); G_TouchTriggers(ent); if (!ent->inuse) { return; } if (ent->groundentity) { if (!wasonground) { if (hitsound) { gi.sound(ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); } } } } /* regular thinking */ SV_RunThink(ent); }
/* ================ SV_Physics ================ */ void SV_Physics (void) { int i; int entity_cap; // For sv_freezenonclients edict_t *ent; // let the progs know that a new frame has started pr_global_struct->self = EDICT_TO_PROG(sv.edicts); pr_global_struct->other = EDICT_TO_PROG(sv.edicts); pr_global_struct->time = sv.time; PR_ExecuteProgram (pr_global_struct->StartFrame); //SV_CheckAllEnts (); // // treat each object in turn // ent = sv.edicts; if (sv.frozen) entity_cap = svs.maxclients + 1; // Only run physics on clients and the world else entity_cap = sv.num_edicts; for (i=0 ; i<entity_cap ; i++, ent = NEXT_EDICT(ent)) // for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent)) { if (ent->free) continue; if (pr_global_struct->force_retouch) { SV_LinkEdict (ent, true); // force retouch even for stationary } if (i > 0 && i <= svs.maxclients) SV_Physics_Client (ent, i); else if (ent->v.movetype == MOVETYPE_PUSH) SV_Physics_Pusher (ent); else if (ent->v.movetype == MOVETYPE_NONE) SV_Physics_None (ent); else if (ent->v.movetype == MOVETYPE_FOLLOW) // Nehahra SV_Physics_Follow (ent); else if (ent->v.movetype == MOVETYPE_NOCLIP) SV_Physics_Noclip (ent); else if (ent->v.movetype == MOVETYPE_STEP) SV_Physics_Step (ent); else if (ent->v.movetype == MOVETYPE_WALK) // Nehahra { if (!SV_RunThink (ent)) return; if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); } else if (ent->v.movetype == MOVETYPE_TOSS || ent->v.movetype == MOVETYPE_BOUNCE || ent->v.movetype == MOVETYPE_FLY || ent->v.movetype == MOVETYPE_FLYMISSILE) SV_Physics_Toss (ent); else Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); } if (pr_global_struct->force_retouch) pr_global_struct->force_retouch--; if (!sv.frozen) sv.time += host_frametime; }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; #ifdef QUAKE2 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); SV_CheckWater (ent); #endif // regular thinking if (!SV_RunThink (ent)) return; #ifdef QUAKE2 if (ent->v.velocity[2] > 0) ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; if ( ((int)ent->v.flags & FL_ONGROUND) ) //@@ if (VectorCompare(ent->v.basevelocity, vec_origin)) return; SV_CheckVelocity (ent); // add gravity if (! ((int)ent->v.flags & FL_ONGROUND) && ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); #else // if onground, return without moving if ( ((int)ent->v.flags & FL_ONGROUND) ) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); #endif // move angles VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); // move origin #ifdef QUAKE2 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif VectorScale (ent->v.velocity, host_frametime, move); trace = SV_PushEntity (ent, move); #ifdef QUAKE2 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif if (trace.fraction == 1) return; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; #ifdef QUAKE2 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) backoff = 2.0; #endif else backoff = 1; ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { #ifdef QUAKE2 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) #else if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) #endif { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = ((int)EDICT_TO_PROG(trace.ent)); VectorCopy (vec3_origin, ent->v.velocity); VectorCopy (vec3_origin, ent->v.avelocity); } } // check for in water SV_CheckWaterTransition (ent); }
// pull the player toward the grapple void CTFGrapplePull(edict_t *self) { vec3_t hookdir, v; float vlen; if (strcmp(self->owner->client->weapon->classname, "weapon_grapple") == 0 && !self->owner->client->newweapon && self->owner->client->weaponstate != WEAPON_FIRING && self->owner->client->weaponstate != WEAPON_ACTIVATING) { CTFResetGrapple(self); return; } if (self->enemy) { if (self->enemy->solid == SOLID_NOT) { CTFResetGrapple(self); return; } if (self->enemy->solid == SOLID_BBOX) { VectorScale(self->enemy->size, 0.5, v); VectorAdd(v, self->enemy->s.origin, v); VectorAdd(v, self->enemy->mins, self->s.origin); gi.linkentity (self); } else VectorCopy(self->enemy->velocity, self->velocity); if (self->enemy->takedamage) { float volume = 1.0; if (self->owner->client->silencer_shots) volume = 0.2; T_Damage (self->enemy, self, self->owner, self->velocity, self->s.origin, vec3_origin, 1, 1, 0, MOD_GRAPPLE); gi.sound (self, CHAN_WEAPON, gi.soundindex("weapons/grapple/grhurt.wav"), volume, ATTN_NORM, 0); } if (self->enemy->deadflag) { // he died CTFResetGrapple(self); return; } } CTFGrappleDrawCable(self); if (self->owner->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY) { // pull player toward grapple // this causes icky stuff with prediction, we need to extend // the prediction layer to include two new fields in the player // move stuff: a point and a velocity. The client should add // that velociy in the direction of the point vec3_t forward, up; AngleVectors (self->owner->client->v_angle, forward, NULL, up); VectorCopy(self->owner->s.origin, v); v[2] += self->owner->viewheight; VectorSubtract (self->s.origin, v, hookdir); vlen = VectorLength(hookdir); if (self->owner->client->ctf_grapplestate == CTF_GRAPPLE_STATE_PULL && vlen < 64) { float volume = 1.0; if (self->owner->client->silencer_shots) volume = 0.2; self->owner->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; gi.sound (self->owner, CHAN_RELIABLE+CHAN_WEAPON, gi.soundindex("weapons/grapple/grhang.wav"), volume, ATTN_NORM, 0); self->owner->client->ctf_grapplestate = CTF_GRAPPLE_STATE_HANG; } VectorNormalize (hookdir); VectorScale(hookdir, CTF_GRAPPLE_PULL_SPEED, hookdir); VectorCopy(hookdir, self->owner->velocity); SV_AddGravity(self->owner); } }
/* ============= 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 ); }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *ground; SV_CheckWater( ent ); // regular thinking if( !SV_RunThink( ent )) return; ground = ent->v.groundentity; if( ent->v.velocity[2] > 0.0f || !SV_IsValidEdict( ground ) || ground->v.flags & (FL_MONSTER|FL_CLIENT) || svgame.globals->changelevel ) { ent->v.flags &= ~FL_ONGROUND; } // if on ground and not moving, return. if( ent->v.flags & FL_ONGROUND && VectorIsNull( ent->v.velocity )) { VectorClear( ent->v.avelocity ); if( VectorIsNull( ent->v.basevelocity )) return; // at rest } SV_CheckVelocity( ent ); // add gravity switch( ent->v.movetype ) { case MOVETYPE_FLY: case MOVETYPE_FLYMISSILE: case MOVETYPE_BOUNCEMISSILE: break; default: SV_AddGravity( ent ); break; } // move angles (with friction) switch( ent->v.movetype ) { case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_AngularMove( ent, host.frametime, ent->v.friction ); break; default: SV_AngularMove( ent, host.frametime, 0.0f ); break; } // move origin // Base velocity is not properly accounted for since this entity will move again // after the bounce without taking it into account VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); SV_CheckVelocity( ent ); VectorScale( ent->v.velocity, host.frametime, move ); VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; SV_CheckVelocity( ent ); if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); return; } if( trace.fraction == 1.0f ) { SV_CheckWaterTransition( ent ); return; } if( ent->v.movetype == MOVETYPE_BOUNCE ) backoff = 2.0f - ent->v.friction; else if( ent->v.movetype == MOVETYPE_BOUNCEMISSILE ) backoff = 2.0f; else backoff = 1.0f; SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff ); // stop if on ground if( trace.plane.normal[2] > 0.7f ) { float vel; VectorAdd( ent->v.velocity, ent->v.basevelocity, move ); vel = DotProduct( move, move ); if( ent->v.velocity[2] < sv_gravity->value * host.frametime ) { // we're rolling on the ground, add static friction. ent->v.groundentity = trace.ent; ent->v.flags |= FL_ONGROUND; ent->v.velocity[2] = 0.0f; } if( vel < 900.0f || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE )) { ent->v.flags |= FL_ONGROUND; ent->v.groundentity = trace.ent; VectorClear( ent->v.avelocity ); VectorClear( ent->v.velocity ); } else { VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move ); VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; } } // check for in water SV_CheckWaterTransition( ent ); }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; // regular thinking if (!SV_RunThink (ent)) return; // if onground, return without moving if (((int)ent->v.flags & FL_ONGROUND)) return; SV_CheckVelocity (ent); // add gravity if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_FLYMISSILE) #ifdef HEXEN2_SUPPORT if ( (!hexen2) || (ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_SWIM)) #endif SV_AddGravity (ent); // move anglesy VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); // move origin VectorScale (ent->v.velocity, host_frametime, move); trace = SV_PushEntity (ent, move); if (trace.fraction == 1) return; if (ent->free) return; if (ent->v.movetype == MOVETYPE_BOUNCE) backoff = 1.5; #ifdef HEXEN2_SUPPORT else if (hexen2 && (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)) { if ((ent->v.solid == SOLID_PHASE) && (((int) trace.ent->v.flags & FL_MONSTER) || ((int) trace.ent->v.movetype == MOVETYPE_WALK))) { return; // Solid phased missiles don't bounce on monsters or players } backoff = 2.0; } #endif else backoff = 1; ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { #ifdef HEXEN2_SUPPORT if ((!hexen2) || (ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) #endif if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) { ent->v.flags = (int)ent->v.flags | FL_ONGROUND; ent->v.groundentity = EDICT_TO_PROG(trace.ent); VectorCopy (vec3_origin, ent->v.velocity); VectorCopy (vec3_origin, ent->v.avelocity); } } // check for in water SV_CheckWaterTransition (ent); }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // vec3_t dir; // airborn monsters should always check for ground // if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; // if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) // SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { //gi.bprintf(PRINT_HIGH,"FLY!\n"); speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { //gi.bprintf(PRINT_HIGH,"SWIM!\n"); //K03 Begin float water_friction; //K03 End speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; //K03 Begin water_friction=(FRAMETIME * control * sv_waterfriction * ent->waterlevel); //newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable)) newspeed = speed; else newspeed = speed - water_friction; //K03 End if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { //K03 Begin float water_friction; //K03 End vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; //K03 Begin water_friction=FRAMETIME*control*friction; //newspeed = speed - FRAMETIME*control*friction; if ( ((ent->myskills.abilities[SUPER_SPEED].current_level < 1) || (ent->myskills.abilities[SUPER_SPEED].disable)) && !(ent->flags & FL_SWIM)) newspeed = speed; else newspeed = speed - water_friction; //K03 End if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->svflags & SVF_MONSTER) { if(!deathmatch->value) mask = MASK_MONSTERSOLID; else mask = MASK_BOTSOLIDX;//MASK_PLAYERSOLID; } else mask = MASK_SOLID; //FIXME: warning - SV_FlyMove() can cause an entity to be freed SV_FlyMove (ent, FRAMETIME, mask); gi.linkentity (ent); // G_TouchTriggers (ent); } else V_TouchSolids(ent); // regular thinking SV_RunThink (ent); }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; qboolean forcethrough = false; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if (ent->groundentity) { V_TouchSolids(ent); return; } VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE && ent->movetype != MOVETYPE_SLIDE // RAFAEL // move type for rippergun projectile && ent->movetype != MOVETYPE_WALLBOUNCE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); if(ent->classname[0] == 'R' && (ent->classname[6] == 'X' || ent->classname[6] == '3')) { ent->groundentity = ent->union_ent; ent->groundentity_linkcount = ent->union_ent->linkcount; VectorCopy (ent->union_ent->velocity, ent->velocity); VectorCopy (ent->union_ent->avelocity, ent->avelocity); VectorAdd(ent->union_ent->s.origin,ent->moveinfo.dir,ent->s.origin); } trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1 && !forcethrough) { // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) backoff = 2.0; // RAFAEL ( else ) else if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // spikeball never stops bouncing if (ent->mtype == M_SPIKEBALL) { float delta = 275 - ent->velocity[2]; // don't get stuck on the ceiling if (trace.plane.normal[2] != -1.0) ent->velocity[2] += delta; // always bounce away from the wall VectorMA(ent->velocity, 100, trace.plane.normal, ent->velocity); } // RAFAEL if (ent->movetype == MOVETYPE_WALLBOUNCE) vectoangles (ent->velocity, ent->s.angles); // stop if on ground // RAFAEL //K03 Begin if (trace.plane.normal[2] > 0.95 && ent->movetype != MOVETYPE_WALLBOUNCE && ent->movetype != MOVETYPE_SLIDE)//was 0.7 { if (ent->velocity[2] < 30/*60*/ || ent->movetype != MOVETYPE_BOUNCE ) //K03 End { // gi.dprintf("SV_Physics_Toss() stopped the entity\n"); ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; if (!ent) { return; } /* regular thinking */ SV_RunThink(ent); /* if not a team captain, so movement will be handled elsewhere */ if (ent->flags & FL_TEAMSLAVE) { return; } if (ent->velocity[2] > 0) { ent->groundentity = NULL; } /* check for the groundentity going away */ if (ent->groundentity) { if (!ent->groundentity->inuse) { ent->groundentity = NULL; } } /* if onground, return without moving */ if (ent->groundentity) { return; } VectorCopy(ent->s.origin, old_origin); SV_CheckVelocity(ent); /* add gravity */ if ((ent->movetype != MOVETYPE_FLY) && (ent->movetype != MOVETYPE_FLYMISSILE) && (ent->movetype != MOVETYPE_WALLBOUNCE)) { SV_AddGravity(ent); } /* move angles */ VectorMA(ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); /* move origin */ VectorScale(ent->velocity, FRAMETIME, move); trace = SV_PushEntity(ent, move); if (!ent->inuse) { return; } if (trace.fraction < 1) { if (ent->movetype == MOVETYPE_WALLBOUNCE) { backoff = 2.0; } else if (ent->movetype == MOVETYPE_BOUNCE) { backoff = 1.5; } else { backoff = 1; } ClipVelocity(ent->velocity, trace.plane.normal, ent->velocity, backoff); if (ent->movetype == MOVETYPE_WALLBOUNCE) { vectoangles(ent->velocity, ent->s.angles); } /* stop if on ground */ if ((trace.plane.normal[2] > 0.7) && (ent->movetype != MOVETYPE_WALLBOUNCE)) { if ((ent->velocity[2] < 60) || (ent->movetype != MOVETYPE_BOUNCE)) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy(vec3_origin, ent->velocity); VectorCopy(vec3_origin, ent->avelocity); } } } /* check for water transition */ wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents(ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) { ent->waterlevel = 1; } else { ent->waterlevel = 0; } if (!wasinwater && isinwater) { gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } else if (wasinwater && !isinwater) { gi.positioned_sound(ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); } /* move teamslaves */ for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy(ent->s.origin, slave->s.origin); gi.linkentity(slave); } }
/* ============= SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ void SV_Physics_Toss (edict_t *ent) { trace_t trace; vec3_t move; float backoff; edict_t *slave; qboolean wasinwater; qboolean isinwater; vec3_t old_origin; // regular thinking SV_RunThink (ent); // if not a team captain, so movement will be handled elsewhere if ( ent->flags & FL_TEAMSLAVE) return; if (ent->velocity[2] > 0) ent->groundentity = NULL; // check for the groundentity going away if (ent->groundentity) if (!ent->groundentity->inuse) ent->groundentity = NULL; // if onground, return without moving if ( ent->groundentity && ent->gravity > 0.0) // PGM - gravity hack return; VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity if (ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE) SV_AddGravity (ent); // move angles VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles); // move origin VectorScale (ent->velocity, FRAMETIME, move); trace = SV_PushEntity (ent, move); if (!ent->inuse) return; if (trace.fraction < 1) { if (ent->movetype == MOVETYPE_BOUNCE) backoff = 1.5; else backoff = 1; ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE ) { ent->groundentity = trace.ent; ent->groundentity_linkcount = trace.ent->linkcount; VectorCopy (vec3_origin, ent->velocity); VectorCopy (vec3_origin, ent->avelocity); } } // if (ent->touch) // ent->touch (ent, trace.ent, &trace.plane, trace.surface); } // check for water transition wasinwater = (ent->watertype & MASK_WATER); ent->watertype = gi.pointcontents (ent->s.origin); isinwater = ent->watertype & MASK_WATER; if (isinwater) ent->waterlevel = 1; else ent->waterlevel = 0; if (!wasinwater && isinwater) gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0); // move teamslaves for (slave = ent->teamchain; slave; slave = slave->teamchain) { VectorCopy (ent->s.origin, slave->s.origin); gi.linkentity (slave); } }
void SV_Physics_Step (edict_t *ent) { qboolean wasonground; qboolean hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < sv_gravity->value*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->svflags & SVF_MONSTER) mask = MASK_MONSTERSOLID; else mask = MASK_SOLID; SV_FlyMove (ent, FRAMETIME, mask); gi.linkentity (ent); // ======== // PGM - reset this every time they move. // G_touchtriggers will set it back if appropriate ent->gravity = 1.0; // ======== G_TouchTriggers (ent); if (!ent->inuse) return; if (ent->groundentity) if (!wasonground) if (hitsound) gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0); } if(!ent->inuse) // PGM g_touchtrigger free problem return; // regular thinking SV_RunThink (ent); }
/* ================ SV_Physics_Client Player character actions ================ */ void SV_Physics_Client (edict_t *ent, int num) { if ( ! svs.clients[num-1].active ) return; // unconnected slot // // call standard client pre-think // pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (pr_global_struct->PlayerPreThink); // // do a move // SV_CheckVelocity (ent); // // decide which move function to call // switch ((int)ent->v.movetype) { case MOVETYPE_NONE: if (!SV_RunThink (ent)) return; break; case MOVETYPE_WALK: if (!SV_RunThink (ent)) return; if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_Physics_Toss (ent); break; case MOVETYPE_FLY: if (!SV_RunThink (ent)) return; SV_CheckWater (ent); SV_FlyMove (ent, host_frametime, NULL); break; case MOVETYPE_NOCLIP: if (!SV_RunThink (ent)) return; ent->v.waterlevel = 0; // Avoid annoying waterjumps in noclip ent->v.watertype = CONTENTS_EMPTY; // Avoid annoying waterjumps in noclip VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); break; default: Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); } // // call standard player post-think // if (ent->v.movetype == MOVETYPE_NOCLIP) SV_LinkEdict (ent, false); // don't touch triggers in noclip else SV_LinkEdict (ent, true); pr_global_struct->time = sv.time; pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (pr_global_struct->PlayerPostThink); }
/* ================ SV_Physics_Client Player character actions ================ */ void SV_Physics_Client (edict_t *ent, int num) { if ( ! svs.clients[num-1].active ) return; // unconnected slot // // call standard client pre-think // pr_global_struct->time = sv.time; pr_global_struct->self = ((int)EDICT_TO_PROG(ent)); PR_ExecuteProgram (pr_global_struct->PlayerPreThink); // // do a move // SV_CheckVelocity (ent); // // decide which move function to call // switch ((int)ent->v.movetype) { case MOVETYPE_NONE: if (!SV_RunThink (ent)) return; break; case MOVETYPE_WALK: if (!SV_RunThink (ent)) return; if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); #ifdef QUAKE2 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif SV_WalkMove (ent); #ifdef QUAKE2 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); #endif break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_Physics_Toss (ent); break; case MOVETYPE_FLY: if (!SV_RunThink (ent)) return; SV_FlyMove (ent, host_frametime, NULL); break; case MOVETYPE_NOCLIP: if (!SV_RunThink (ent)) return; VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); break; default: Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); } // // call standard player post-think // SV_LinkEdict (ent, true); pr_global_struct->time = sv.time; pr_global_struct->self = ((int)EDICT_TO_PROG(ent)); PR_ExecuteProgram (pr_global_struct->PlayerPostThink); }
/* * G_BoxSlideMove * calls GS_SlideMove for edict_t and triggers touch functions of touched objects */ int G_BoxSlideMove( edict_t *ent, int contentmask, float slideBounce, float friction ) { int i; move_t entMove; int blockedmask = 0; float oldVelocity; memset( &entMove, 0, sizeof( move_t ) ); oldVelocity = VectorLength( ent->velocity ); if( !ent->groundentity ) { SV_AddGravity( ent ); } else { // horizontal friction G_AddGroundFriction( ent, friction ); } entMove.numClipPlanes = 0; entMove.numtouch = 0; if( oldVelocity > 0 ) { VectorCopy( ent->s.origin, entMove.origin ); VectorCopy( ent->velocity, entMove.velocity ); VectorCopy( ent->r.mins, entMove.mins ); VectorCopy( ent->r.maxs, entMove.maxs ); entMove.remainingTime = FRAMETIME; VectorSet( entMove.gravityDir, 0, 0, -1 ); entMove.slideBounce = slideBounce; entMove.groundEntity = ( ent->groundentity == NULL ) ? -1 : ENTNUM( ent->groundentity ); entMove.passent = ENTNUM( ent ); entMove.contentmask = contentmask; blockedmask = GS_SlideMove( &entMove ); // update with the new values VectorCopy( entMove.origin, ent->s.origin ); VectorCopy( entMove.velocity, ent->velocity ); ent->groundentity = ( entMove.groundEntity == -1 ) ? NULL : &game.edicts[entMove.groundEntity]; GClip_LinkEntity( ent ); } // call touches if( contentmask != 0 ) { edict_t *other; GClip_TouchTriggers( ent ); // touch other objects for( i = 0; i < entMove.numtouch; i++ ) { other = &game.edicts[entMove.touchents[i]]; if( other->r.svflags & SVF_PROJECTILE ) { continue; } G_CallTouch( other, ent, NULL, 0 ); // if self touch function, fire up touch and if freed stop G_CallTouch( ent, other, NULL, 0 ); if( !ent->r.inuse ) { // it may have been freed by the touch function break; } } } if( ent->r.inuse ) { G_CheckGround( ent ); if( ent->groundentity && VectorLength( ent->velocity ) <= 1 && oldVelocity > 1 ) { VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } return blockedmask; }
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_Physics_Step (edict_t *ent) { bool wasonground; bool hitsound = false; float *vel; float speed, newspeed, control; float friction; edict_t *groundentity; int mask; // airborn monsters should always check for ground if (!ent->groundentity) M_CheckGround (ent); groundentity = ent->groundentity; SV_CheckVelocity (ent); if (groundentity) wasonground = true; else wasonground = false; if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: // flying monsters // swimming monsters who are in the water if (! wasonground) if (!(ent->flags & FL_FLY)) if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) { if (ent->velocity[2] < level.gravity*-0.1) hitsound = true; if (ent->waterlevel == 0) SV_AddGravity (ent); } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (FRAMETIME * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } // friction for flying monsters that have been given vertical velocity if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) { speed = fabs(ent->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; ent->velocity[2] *= newspeed; } if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) { // apply friction // let dead monsters who aren't completely onground slide if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) if (!(ent->health <= 0.0 && !M_CheckBottom(ent))) { vel = ent->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { friction = sv_friction; control = speed < sv_stopspeed ? sv_stopspeed : speed; newspeed = speed - FRAMETIME*control*friction; if (newspeed < 0) newspeed = 0; newspeed /= speed; vel[0] *= newspeed; vel[1] *= newspeed; } } if (ent->r.svflags & SVF_MONSTER) mask = MASK_MONSTERSOLID; else mask = MASK_SOLID; SV_FlyMove (ent, FRAMETIME, mask); GClip_LinkEntity (ent); GClip_TouchTriggers (ent); if (ent->groundentity) if (!wasonground) if (hitsound) G_Sound (ent, 0, trap_SoundIndex( S_LAND ), ATTN_NORM); } }
/* * SV_Physics_Toss * * Toss, bounce, and fly movement. When onground, do nothing. * * FIXME: This function needs a serious rewrite */ static void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *slave; bool wasinwater; bool isinwater; vec3_t old_origin; float oldSpeed; // if not a team captain, so movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } // refresh the ground entity if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { if( ent->velocity[2] > 0.1f ) { ent->groundentity = NULL; } } if( ent->groundentity && ent->groundentity != world && !ent->groundentity->r.inuse ) { ent->groundentity = NULL; } oldSpeed = VectorLength( ent->velocity ); if( ent->groundentity ) { if( !oldSpeed ) { return; } if( ent->movetype == MOVETYPE_TOSS ) { if( ent->velocity[2] >= 8 ) { ent->groundentity = NULL; } else { VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); return; } } } VectorCopy( ent->s.origin, old_origin ); if( ent->accel != 0 ) { if( ent->accel < 0 && VectorLength( ent->velocity ) < 50 ) { VectorClear( ent->velocity ); } else { vec3_t acceldir; VectorNormalize2( ent->velocity, acceldir ); VectorScale( acceldir, ent->accel * FRAMETIME, acceldir ); VectorAdd( ent->velocity, acceldir, ent->velocity ); } } SV_CheckVelocity( ent ); // add gravity if( ent->movetype != MOVETYPE_FLY && !ent->groundentity ) { SV_AddGravity( ent ); } // move angles VectorMA( ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles ); // move origin VectorScale( ent->velocity, FRAMETIME, move ); trace = SV_PushEntity( ent, move ); if( !ent->r.inuse ) { return; } if( trace.fraction < 1.0f ) { if( ent->movetype == MOVETYPE_BOUNCE ) { backoff = 1.5; } else if( ent->movetype == MOVETYPE_BOUNCEGRENADE ) { backoff = 1.5; } else { backoff = 1; } GS_ClipVelocity( ent->velocity, trace.plane.normal, ent->velocity, backoff ); // stop if on ground if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { // stop dead on allsolid // LA: hopefully will fix grenades bouncing down slopes // method taken from Darkplaces sourcecode if( trace.allsolid || ( ISWALKABLEPLANE( &trace.plane ) && fabs( DotProduct( trace.plane.normal, ent->velocity ) ) < 40 ) ) { ent->groundentity = &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } else { // in movetype_toss things stop dead when touching ground #if 0 G_CheckGround( ent ); if( ent->groundentity ) { #else // walkable or trapped inside solid brush if( trace.allsolid || ISWALKABLEPLANE( &trace.plane ) ) { ent->groundentity = trace.ent < 0 ? world : &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; #endif VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } } // check for water transition wasinwater = ( ent->watertype & MASK_WATER ) ? true : false; ent->watertype = G_PointContents( ent->s.origin ); isinwater = ent->watertype & MASK_WATER ? true : false; // never allow items in CONTENTS_NODROP if( ent->item && ( ent->watertype & CONTENTS_NODROP ) ) { G_FreeEdict( ent ); return; } if( isinwater ) { ent->waterlevel = 1; } else { ent->waterlevel = 0; } if( !wasinwater && isinwater ) { G_PositionedSound( old_origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( wasinwater && !isinwater ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } // move teamslaves for( slave = ent->teamchain; slave; slave = slave->teamchain ) { VectorCopy( ent->s.origin, slave->s.origin ); GClip_LinkEntity( slave ); } } //============================================================================ void SV_Physics_LinearProjectile( edict_t *ent ) { vec3_t start, end; int mask; float startFlyTime, endFlyTime; trace_t trace; int old_waterLevel; // if not a team captain movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } old_waterLevel = ent->waterlevel; mask = ( ent->r.clipmask ) ? ent->r.clipmask : MASK_SOLID; // find it's current position given the starting timeStamp startFlyTime = (float)( max( game.prevServerTime - ent->s.linearMovementTimeStamp, 0 ) ) * 0.001f; endFlyTime = (float)( game.serverTime - ent->s.linearMovementTimeStamp ) * 0.001f; VectorMA( ent->s.linearMovementBegin, startFlyTime, ent->s.linearMovementVelocity, start ); VectorMA( ent->s.linearMovementBegin, endFlyTime, ent->s.linearMovementVelocity, end ); G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); VectorCopy( trace.endpos, ent->s.origin ); GClip_LinkEntity( ent ); SV_Impact( ent, &trace ); if( !ent->r.inuse ) { // the projectile may be freed if touched something return; } // update some data required for the transmission //VectorCopy( ent->velocity, ent->s.linearMovementVelocity ); GClip_TouchTriggers( ent ); ent->groundentity = NULL; // projectiles never have ground entity ent->waterlevel = ( G_PointContents4D( ent->s.origin, ent->timeDelta ) & MASK_WATER ) ? true : false; if( !old_waterLevel && ent->waterlevel ) { G_PositionedSound( start, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( old_waterLevel && !ent->waterlevel ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } }
/* ================ SV_Physics_Client Player character actions ================ */ void SV_Physics_Client (edict_t *ent, int num) { client_t *cl; vec3_t v; qboolean was_angle_set; cl = &svs.clients[num-1]; if (!cl->active) return; // unconnected slot // call standard client pre-think PR_GLOBAL(time) = sv.time; PR_GLOBAL(self) = EDICT_TO_PROG(ent); PR_ExecuteProgram (PR_GLOBAL(PlayerPreThink)); // for cutscene hack (see below) if (isDedicated || (num != 1)) was_angle_set = false; // do it on local client only else was_angle_set = (ent->v.fixangle != 0); // do a move SV_CheckVelocity (ent); // decide which move function to call switch ((int)ent->v.movetype) { case MOVETYPE_NONE: if (!SV_RunThink(ent)) return; break; case MOVETYPE_WALK: if (!SV_RunThink(ent)) return; if (!SV_CheckWater(ent) && !((int)ent->v.flags & FL_WATERJUMP)) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); break; case MOVETYPE_TOSS: case MOVETYPE_BOUNCE: SV_Physics_Toss (ent); break; case MOVETYPE_FLY: #ifdef HEXEN2_SUPPORT case MOVETYPE_SWIM: #endif if (!SV_RunThink(ent)) return; SV_FlyMove (ent, host_frametime, NULL); break; case MOVETYPE_NOCLIP: if (!SV_RunThink(ent)) return; VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); break; default: Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); } // JDH: hack for cutscenes made by Darin McNeil's Cutscene Construction Kit: // (note that the extra precision is noticeable only if the viewangles // are sent from server to client as 2-byte values; hence the addition // of the new svc_setpreciseangle message code) if (was_angle_set && (ent->v.view_ofs[2] == 0) && host_cutscenehack.value && !strcmp (pr_strings + ent->v.classname, "camera")) { // - when camera changes back to player, classname remains "camera" for // 1 frame, but movedir is no longer valid. So as an additional check, // I verify that view_ofs[2] is still 0 // - early version(s?) of Cutscene Construction Kit don't move the camera, // so movedir is not used. I determine the version by checking *when* // the viewangle is set: early version does it in the .think function; // later ones in PlayerPreThink. was_angle_set will be true only if // it was changed in PlayerPreThink //if (!sv_oldprotocol.value) { v[0] = ent->v.movedir[0] - ent->v.origin[0]; v[1] = ent->v.movedir[1] - ent->v.origin[1]; v[2] = ent->v.origin[2] - ent->v.movedir[2]; //vectoangles (v, ent->v.angles); vectoangles (v, cl->cutscene_viewangles); } if (!cl->in_cutscene) { int i; edict_t *ed; // by this time, the player's viewangles have already been changed. // But the dummy entity spawned in place of the player has the values for (i = 1 ; i < sv.num_edicts ; i++) { // get the current server version ed = EDICT_NUM(i); if (ed->free) continue; if (!strcmp(pr_strings + ed->v.classname, "dummy")) { VectorCopy (ed->v.angles, cl->prev_viewangles); break; } } cl->in_cutscene = true; } //sv.found_cutscene = true; } else { if (cl->in_cutscene) { // I'm not sure why, but last viewangle while in_cutscene isn't final angle ent->v.fixangle = 1; VectorCopy (cl->prev_viewangles, ent->v.angles); cl->in_cutscene = false; } } SV_LinkEdict (ent, true); PR_GLOBAL(time) = sv.time; PR_GLOBAL(self) = EDICT_TO_PROG(ent); // JDH: another hack, this time for progs that lack CycleWeaponReverse if ((ent->v.impulse == 12.0) && ((sv_imp12hack.value >= 2) || (sv_imp12hack.value && !pr_handles_imp12)) && !ent->v.deadflag && (ent->v.view_ofs[0] || ent->v.view_ofs[1] || ent->v.view_ofs[2])) { eval_t *val = GETEDICTFIELD(ent, eval_attack_finished); if (val && (sv.time >= val->_float)) { SV_CycleWeaponReverse (ent); } } // call standard player post-think PR_ExecuteProgram (PR_GLOBAL(PlayerPostThink)); }