/* ============= SV_CheckStuck This is a big hack to try and fix the rare case of getting stuck in the world clipping hull. ============= */ void SV_CheckStuck(edict_t * ent) { int i, j; int z; vec3_t org; if (!SV_TestEntityPosition(ent)) { VectorCopy(ent->v.origin, ent->v.oldorigin); return; } VectorCopy(ent->v.origin, org); VectorCopy(ent->v.oldorigin, ent->v.origin); if (!SV_TestEntityPosition(ent)) { Con_Printf("Unstuck.\n"); SV_LinkEdict(ent, true); return; } for (z = 0; z < 18; z++) for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { ent->v.origin[0] = org[0] + i; ent->v.origin[1] = org[1] + j; ent->v.origin[2] = org[2] + z; if (!SV_TestEntityPosition(ent)) { Con_DPrintf("Unstuck.\n"); SV_LinkEdict(ent, true); return; } } VectorCopy(org, ent->v.origin); Con_DPrintf("player is stuck.\n"); }
/* ================ SV_CheckAllEnts ================ */ void SV_CheckAllEnts(void) { int e; edict_t *check; // see if any solid entities are inside the final position check = NEXT_EDICT(sv.edicts); for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; if (SV_TestEntityPosition(check)) Con_Printf("entity in invalid position\n"); } }
/* ============ SV_PushRotate ============ */ void SV_PushRotate (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t move, a, amove; vec3_t entorig, pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; vec3_t org, org2; vec3_t forward, right, up; if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) amove[i] = pusher->v.avelocity[i] * movetime; VectorSubtract (vec3_origin, amove, a); AngleVectors (a, forward, right, up); VectorCopy (pusher->v.angles, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.angles, amove, pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE #ifdef QUAKE2 || check->v.movetype == MOVETYPE_FOLLOW #endif || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= pusher->v.absmax[0] || check->v.absmin[1] >= pusher->v.absmax[1] || check->v.absmin[2] >= pusher->v.absmax[2] || check->v.absmax[0] <= pusher->v.absmin[0] || check->v.absmax[1] <= pusher->v.absmin[1] || check->v.absmax[2] <= pusher->v.absmin[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // calculate destination position VectorSubtract (check->v.origin, pusher->v.origin, org); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move); // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); pusher->v.solid = SOLID_BSP; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.angles); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = ((int)EDICT_TO_PROG(pusher)); pr_global_struct->other = ((int)EDICT_TO_PROG(check)); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); SV_LinkEdict (moved_edict[i], false); } return; } else { VectorAdd (check->v.angles, amove, check->v.angles); } } }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; float solid_backup; //movetype_push error fix - Eradicator if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE #ifdef QUAKE2 || check->v.movetype == MOVETYPE_FOLLOW #endif || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; //START - movetype_push error fix - Eradicator solid_backup = pusher->v.solid; if ( solid_backup == SOLID_BSP || solid_backup == SOLID_BBOX || solid_backup == SOLID_SLIDEBOX ) { //END - movetype_push error fix - Eradicator // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); //pusher->v.solid = SOLID_BSP; //Old pusher->v.solid = solid_backup; //movetype_push error fix - Eradicator // if it is still inside the pusher, block block = SV_TestEntityPosition (check); } //movetype_push error fix - Eradicator else block = NULL; if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.origin); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = ((int)EDICT_TO_PROG(pusher)); pr_global_struct->other = ((int)EDICT_TO_PROG(check)); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }
/* ============ SV_Push Objects need to be moved back on a failed push, otherwise riders would continue to slide. ============ */ qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) { int i, e; edict_t *check, *block; vec3_t mins, maxs; pushed_t *p; vec3_t org, org2, move2, forward, right, up; // clamp the move to 1/8 units, so the position will // be accurate for client side prediction for (i=0 ; i<3 ; i++) { float temp; temp = move[i]*8.0; if (temp > 0.0) temp += 0.5; else temp -= 0.5; move[i] = 0.125 * (int)temp; } // find the bounding box for (i=0 ; i<3 ; i++) { mins[i] = pusher->absmin[i] + move[i]; maxs[i] = pusher->absmax[i] + move[i]; } // we need this for pushing things later VectorSubtract (vec3_origin, amove, org); AngleVectors (org, forward, right, up); // save the pusher's original position pushed_p->ent = pusher; VectorCopy (pusher->s.origin, pushed_p->origin); VectorCopy (pusher->s.angles, pushed_p->angles); if (pusher->client) pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; pushed_p++; // move the pusher to it's final position VectorAdd (pusher->s.origin, move, pusher->s.origin); VectorAdd (pusher->s.angles, amove, pusher->s.angles); gi.linkentity (pusher); // see if any solid entities are inside the final position check = g_edicts+1; for (e = 1; e < globals.num_edicts; e++, check++) { if (!check->inuse) continue; if (check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_STOP || check->movetype == MOVETYPE_NONE || check->movetype == MOVETYPE_NOCLIP) continue; if (!check->area.prev) continue; // not linked in anywhere // if the entity is standing on the pusher, it will definitely be moved if (check->groundentity != pusher) { // see if the ent needs to be tested if ( check->absmin[0] >= maxs[0] || check->absmin[1] >= maxs[1] || check->absmin[2] >= maxs[2] || check->absmax[0] <= mins[0] || check->absmax[1] <= mins[1] || check->absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher)) { // move this entity pushed_p->ent = check; VectorCopy (check->s.origin, pushed_p->origin); VectorCopy (check->s.angles, pushed_p->angles); pushed_p++; // try moving the contacted entity VectorAdd (check->s.origin, move, check->s.origin); if (check->client) { // FIXME: doesn't rotate monsters? check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; } // figure movement due to the pusher's amove VectorSubtract (check->s.origin, pusher->s.origin, org); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move2); VectorAdd (check->s.origin, move2, check->s.origin); // may have pushed them off an edge if (check->groundentity != pusher) check->groundentity = NULL; block = SV_TestEntityPosition (check); if (!block) { // pushed ok gi.linkentity (check); // impact? continue; } // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed // FIXME: this doesn't acount for rotation VectorSubtract (check->s.origin, move, check->s.origin); block = SV_TestEntityPosition (check); if (!block) { pushed_p--; continue; } } // save off the obstacle so we can call the block function obstacle = check; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for (p=pushed_p-1 ; p>=pushed ; p--) { VectorCopy (p->origin, p->ent->s.origin); VectorCopy (p->angles, p->ent->s.angles); if (p->ent->client) { p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; } gi.linkentity (p->ent); } return false; } //FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger for (p=pushed_p-1 ; p>=pushed ; p--) G_TouchTriggers (p->ent); return true; }
/* ============ SV_Push ============ */ qboolean SV_Push (edict_t *pusher, vec3_t move) { int i, e; edict_t *check, *block; vec3_t mins, maxs; vec3_t pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; for (i=0 ; i<3 ; i++) { mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition (check); pusher->v.solid = SOLID_BSP; if (block) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // try moving the contacted entity VectorAdd (check->v.origin, move, check->v.origin); block = SV_TestEntityPosition (check); if (!block) { // pushed ok SV_LinkEdict (check, false); continue; } // if it is ok to leave in the old position, do it VectorSubtract (check->v.origin, move, check->v.origin); block = SV_TestEntityPosition (check); if (!block) { num_moved--; continue; } // if it is still inside the pusher, block if (check->v.mins[0] == check->v.maxs[0]) { SV_LinkEdict (check, false); continue; } if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); SV_LinkEdict (check, false); continue; } VectorCopy (pushorig, pusher->v.origin); SV_LinkEdict (pusher, false); // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return false; } return true; }
qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) { int i, e; edict_t *check, *block; vec3_t mins, maxs; pushed_t *p; vec3_t org, org2, move2, forward, right, up; // clamp the move to 1/8 units, so the position will // be accurate for client side prediction for (i=0 ; i<3 ; i++) { float temp; temp = move[i]*8.0; if (temp > 0.0) temp += 0.5; else temp -= 0.5; move[i] = 0.125 * (int)temp; } // find the bounding box for (i=0 ; i<3 ; i++) { mins[i] = pusher->absmin[i] + move[i]; maxs[i] = pusher->absmax[i] + move[i]; } // we need this for pushing things later VectorSubtract (vec3_origin, amove, org); AngleVectors (org, forward, right, up); // save the pusher's original position pushed_p->ent = pusher; VectorCopy (pusher->s.origin, pushed_p->origin); VectorCopy (pusher->s.angles, pushed_p->angles); if (pusher->client) pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; pushed_p++; // move the pusher to it's final position VectorAdd (pusher->s.origin, move, pusher->s.origin); VectorAdd (pusher->s.angles, amove, pusher->s.angles); gi.linkentity (pusher); // see if any solid entities are inside the final position check = g_edicts+1; for (e = 1; e < globals.num_edicts; e++, check++) { if (!check->inuse) continue; if (check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_STOP || check->movetype == MOVETYPE_NONE || check->movetype == MOVETYPE_NOCLIP) continue; if (!check->area.prev) continue; // not linked in anywhere // Ridah, dead monsters don't block door if (check->svflags & SVF_MONSTER && check->health <= 0) { //gi.dprintf( "SV_Push todo: Gib blocking characters\n"); continue; } // Ridah, dead clients shouldn't block doors if (check->client && (check->health <= 0 || !check->solid)) continue; // if the entity is standing on the pusher, it will definitely be moved if (check->groundentity != pusher) { // see if the ent needs to be tested if ( check->absmin[0] >= maxs[0] || check->absmin[1] >= maxs[1] || check->absmin[2] >= maxs[2] || check->absmax[0] <= mins[0] || check->absmax[1] <= mins[1] || check->absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // Ridah, doors don't push if ((pusher->blocked == door_blocked) && !pusher->style && !(check->svflags & SVF_MONSTER)) { // move it back VectorSubtract (pusher->s.origin, move, pusher->s.origin); VectorSubtract (pusher->s.angles, amove, pusher->s.angles); gi.linkentity (pusher); obstacle = check; return false; } if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher)) { // move to a visible node if ((check->svflags & SVF_MONSTER) && !check->goal_ent) { extern void AI_FreeAndClearGoalEnt( edict_t *self ); node_t *node; if (node = NAV_GetClosestNode( check, VIS_PARTIAL, false, false )) { check->goal_ent = G_Spawn(); check->goal_ent->owner = check; VectorCopy( node->origin, check->goal_ent->s.origin ); check->goal_ent->think = AI_FreeAndClearGoalEnt; check->goal_ent->nextthink = level.time + 3; check->goal_ent->dmg_radius = 0; // get real close to it if (check->cast_info.move_runwalk) check->cast_info.currentmove = check->cast_info.move_runwalk; else check->cast_info.currentmove = check->cast_info.move_run; } } // move this entity pushed_p->ent = check; VectorCopy (check->s.origin, pushed_p->origin); VectorCopy (check->s.angles, pushed_p->angles); pushed_p++; // try moving the contacted entity VectorAdd (check->s.origin, move, check->s.origin); if (check->client) { // FIXME: doesn't rotate monsters? check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; // JOSEPH 5-APR-99 if (pusher->touch) pusher->touch(pusher, check, 0, 0); // END JOSEPH } // figure movement due to the pusher's amove VectorSubtract (check->s.origin, pusher->s.origin, org); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move2); VectorAdd (check->s.origin, move2, check->s.origin); // may have pushed them off an edge if (check->groundentity != pusher) check->groundentity = NULL; block = SV_TestEntityPosition (check); if (!block) { // pushed ok gi.linkentity (check); // impact? continue; } // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed // FIXME: this doesn't acount for rotation VectorSubtract (check->s.origin, move, check->s.origin); block = SV_TestEntityPosition (check); if (!block) { pushed_p--; continue; } } // save off the obstacle so we can call the block function obstacle = check; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for (p=pushed_p-1 ; p>=pushed ; p--) { VectorCopy (p->origin, p->ent->s.origin); VectorCopy (p->angles, p->ent->s.angles); if (p->ent->client) { p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; } gi.linkentity (p->ent); } return false; } //FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger for (p=pushed_p-1 ; p>=pushed ; p--) G_TouchTriggers (p->ent); return true; }
// [18/5/2013] TODO: Merge with SV_PushMove ~hogsy static void Server_PushRotate(edict_t *pusher,float movetime) { int i,e,num_moved,slaves_moved; edict_t *check,*block,*moved_edict[MAX_EDICTS],*ground,*slave,*master; vec3_t move,a,amove,entorig,pushorig,moved_from[MAX_EDICTS],org,org2,forward,right,up; bool bMoveIt; for (i = 0; i < 3; i++) amove[i] = pusher->v.avelocity[i] * movetime; Math_VectorNegate(amove,a); Math_AngleVectors(a,forward,right,up); Math_VectorCopy(pusher->v.angles,pushorig); // move the pusher to it's final position Math_VectorAdd(pusher->v.angles,amove,pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); slaves_moved = 0; master = pusher; while(master->v.aiment) { slave = PROG_TO_EDICT(master->v.aiment); slaves_moved++; Math_VectorCopy (slave->v.angles, moved_from[MAX_EDICTS - slaves_moved]); moved_edict[MAX_EDICTS - slaves_moved] = slave; if (slave->v.movedir[PITCH]) slave->v.angles[PITCH] = master->v.angles[PITCH]; else slave->v.angles[PITCH] += slave->v.avelocity[PITCH] * movetime; if (slave->v.movedir[YAW]) slave->v.angles[YAW] = master->v.angles[YAW]; else slave->v.angles[YAW] += slave->v.avelocity[YAW] * movetime; if (slave->v.movedir[ROLL]) slave->v.angles[ROLL] = master->v.angles[ROLL]; else slave->v.angles[ROLL] += slave->v.avelocity[ROLL] * movetime; slave->v.ltime = master->v.ltime; SV_LinkEdict(slave,false); master = slave; } // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definitely be moved bMoveIt = false; ground = check->v.groundentity; if(check->v.flags & FL_ONGROUND) { if (ground == pusher) bMoveIt = true; else { for (i = 0; i < slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { bMoveIt = true; break; } } } } if(!bMoveIt) { if( check->v.absmin[0] >= pusher->v.absmax[0] || check->v.absmin[1] >= pusher->v.absmax[1] || check->v.absmin[2] >= pusher->v.absmax[2] || check->v.absmax[0] <= pusher->v.absmin[0] || check->v.absmax[1] <= pusher->v.absmin[1] || check->v.absmax[2] <= pusher->v.absmin[2]) { for (i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS-i-1]; if( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) continue; } // See if the ent's bbox is inside the pusher's final position if(!SV_TestEntityPosition(check)) continue; } // remove the onground flag for non-players if(check->v.movetype != MOVETYPE_WALK) check->v.flags = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // calculate destination position Math_VectorSubtract(check->v.origin,pusher->v.origin,org); org2[0] = Math_DotProduct(org,forward); org2[1] = -Math_DotProduct(org,right); org2[2] = Math_DotProduct(org,up); Math_VectorSubtract (org2,org,move); // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? if(check->monster.iType != 1) { #if 0 vec3_t vYaw; vYaw[YAW] = Math_AngleMod(pusher->v.angles[YAW]+check->v.angles[YAW]); Con_Printf("%i %i\n",(int)check->v.angles[YAW],(int)vYaw[YAW]); //check->v.angles[YAW] = vYaw[YAW]; //check->v.angles[YAW] = Math_AngleMod(vYaw[YAW]); #endif // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorAdd(moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] += amove[YAW]/2.0f; SV_LinkEdict(moved_edict[i],false); } } pusher->Physics.iSolid = SOLID_BSP; // If it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.angles); SV_LinkEdict(pusher,false); pusher->v.ltime -= movetime; for(i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; Math_VectorCopy(moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict(slave,false); slave->v.ltime -= movetime; } // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) pusher->v.blocked(pusher,check); // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) Math_VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict(moved_edict[i],false); } return; } } }
void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t **moved_edict; //johnfitz -- dynamically allocate vec3_t *moved_from; //johnfitz -- dynamically allocate int mark; //johnfitz if(!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } Math_VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position Math_VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict(pusher,false); //johnfitz -- dynamically allocate mark = Hunk_LowMark (); moved_edict = (edict_t**)Hunk_Alloc(sv.num_edicts*sizeof(edict_t*)); moved_from = (vec3_t(*))Hunk_Alloc (sv.num_edicts*sizeof(vec3_t)); //johnfitz // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if(!((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher)) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); pusher->Physics.iSolid = SOLID_BSP; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.origin); SV_LinkEdict(pusher,false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if(pusher->v.blocked) { pr_global_struct.self = EDICT_TO_PROG(pusher); pr_global_struct.eOther = check; pusher->v.blocked(pusher,check); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { Math_VectorCopy(moved_from[i],moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } Hunk_FreeToLowMark (mark); //johnfitz return; } } Hunk_FreeToLowMark (mark); //johnfitz }
/* * SV_Push * * Objects need to be moved back on a failed push, * otherwise riders would continue to slide. */ static bool SV_Push( edict_t *pusher, vec3_t move, vec3_t amove ) { int i, e; edict_t *check, *block; vec3_t mins, maxs; pushed_t *p; mat3_t axis; vec3_t org, org2, move2; // find the bounding box for( i = 0; i < 3; i++ ) { mins[i] = pusher->r.absmin[i] + move[i]; maxs[i] = pusher->r.absmax[i] + move[i]; } // we need this for pushing things later VectorNegate( amove, org ); AnglesToAxis( org, axis ); // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->s.origin, pushed_p->origin ); VectorCopy( pusher->s.angles, pushed_p->angles ); if( pusher->r.client ) { VectorCopy( pusher->r.client->ps.pmove.velocity, pushed_p->pmove_origin ); pushed_p->yaw = pusher->r.client->ps.viewangles[YAW]; } pushed_p++; // move the pusher to its final position VectorAdd( pusher->s.origin, move, pusher->s.origin ); VectorAdd( pusher->s.angles, amove, pusher->s.angles ); GClip_LinkEntity( pusher ); // see if any solid entities are inside the final position check = game.edicts + 1; for( e = 1; e < game.numentities; e++, check++ ) { if( !check->r.inuse ) { continue; } if( check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_STOP || check->movetype == MOVETYPE_NONE || check->movetype == MOVETYPE_NOCLIP ) { continue; } if( !check->areagrid[0].prev ) { continue; // not linked in anywhere } // if the entity is standing on the pusher, it will definitely be moved if( check->groundentity != pusher ) { // see if the ent needs to be tested if( check->r.absmin[0] >= maxs[0] || check->r.absmin[1] >= maxs[1] || check->r.absmin[2] >= maxs[2] || check->r.absmax[0] <= mins[0] || check->r.absmax[1] <= mins[1] || check->r.absmax[2] <= mins[2] ) { continue; } // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check ) ) { continue; } } if( ( pusher->movetype == MOVETYPE_PUSH ) || ( check->groundentity == pusher ) ) { // move this entity pushed_p->ent = check; VectorCopy( check->s.origin, pushed_p->origin ); VectorCopy( check->s.angles, pushed_p->angles ); pushed_p++; // try moving the contacted entity VectorAdd( check->s.origin, move, check->s.origin ); if( check->r.client ) { // FIXME: doesn't rotate monsters? VectorAdd( check->r.client->ps.pmove.origin, move, check->r.client->ps.pmove.origin ); check->r.client->ps.viewangles[YAW] += amove[YAW]; } // figure movement due to the pusher's amove VectorSubtract( check->s.origin, pusher->s.origin, org ); Matrix3_TransformVector( axis, org, org2 ); VectorSubtract( org2, org, move2 ); VectorAdd( check->s.origin, move2, check->s.origin ); if( check->movetype != MOVETYPE_BOUNCEGRENADE ) { // may have pushed them off an edge if( check->groundentity != pusher ) { check->groundentity = NULL; } } block = SV_TestEntityPosition( check ); if( !block ) { // pushed ok GClip_LinkEntity( check ); // impact? continue; } else { // try to fix block // if it is ok to leave in the old position, do it // this is only relevant for riding entities, not pushed VectorSubtract( check->s.origin, move, check->s.origin ); VectorSubtract( check->s.origin, move2, check->s.origin ); block = SV_TestEntityPosition( check ); if( !block ) { pushed_p--; continue; } } } // save off the obstacle so we can call the block function obstacle = check; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= pushed; p-- ) { VectorCopy( p->origin, p->ent->s.origin ); VectorCopy( p->angles, p->ent->s.angles ); if( p->ent->r.client ) { VectorCopy( p->pmove_origin, p->ent->r.client->ps.pmove.origin ); p->ent->r.client->ps.viewangles[YAW] = p->yaw; } GClip_LinkEntity( p->ent ); } return false; } //FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger for( p = pushed_p - 1; p >= pushed; p-- ) GClip_TouchTriggers( p->ent ); return true; }
/* ============ SV_PushRotate ============ */ static edict_t *SV_PushRotate( edict_t *pusher, float movetime ) { int i, e, block, oldsolid; matrix4x4 start_l, end_l; vec3_t lmove, amove; sv_pushed_t *p, *pushed_p; vec3_t org, org2, temp; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) amove[i] = pusher->v.avelocity[i] * movetime; // create pusher initial position Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f ); pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_AngularMove( pusher, movetime, pusher->v.friction ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // create pusher final position Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f ); // see if any solid entities are inside the final position for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher )) { if( check->v.absmin[0] >= pusher->v.absmax[0] || check->v.absmin[1] >= pusher->v.absmax[1] || check->v.absmin[2] >= pusher->v.absmax[2] || check->v.absmax[0] <= pusher->v.absmin[0] || check->v.absmax[1] <= pusher->v.absmin[1] || check->v.absmax[2] <= pusher->v.absmin[2] ) continue; // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check, NULL )) continue; } // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p->fixangle = check->v.fixangle; pushed_p++; // calculate destination position if( check->v.movetype == MOVETYPE_PUSHSTEP || check->v.movetype == MOVETYPE_STEP ) VectorAverage( check->v.absmin, check->v.absmax, org ); else VectorCopy( check->v.origin, org ); Matrix4x4_VectorITransform( start_l, org, temp ); Matrix4x4_VectorTransform( end_l, temp, org2 ); VectorSubtract( org2, org, lmove ); // i can't clear FL_ONGROUND in all cases because many bad things may be happen if( check->v.movetype != MOVETYPE_WALK ) { if( lmove[2] != 0.0f ) check->v.flags &= ~FL_ONGROUND; if( lmove[2] < 0.0f && !pusher->v.dmg ) lmove[2] = 0.0f; // let's the free falling } // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, amove, &block ); pusher->v.solid = oldsolid; // pushed entity blocked by wall if( block && check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); p->ent->v.fixangle = p->fixangle; } return check; } } return NULL; }
/* ============ SV_PushMove ============ */ static edict_t *SV_PushMove( edict_t *pusher, float movetime ) { int i, e, block; int num_moved, oldsolid; vec3_t mins, maxs, lmove; sv_pushed_t *p, *pushed_p; edict_t *check; if( svgame.globals->changelevel || VectorIsNull( pusher->v.velocity )) { pusher->v.ltime += movetime; return NULL; } for( i = 0; i < 3; i++ ) { lmove[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + lmove[i]; maxs[i] = pusher->v.absmax[i] + lmove[i]; } pushed_p = svgame.pushed; // save the pusher's original position pushed_p->ent = pusher; VectorCopy( pusher->v.origin, pushed_p->origin ); VectorCopy( pusher->v.angles, pushed_p->angles ); pushed_p++; // move the pusher to it's final position SV_LinearMove( pusher, movetime, 0.0f ); SV_LinkEdict( pusher, false ); pusher->v.ltime += movetime; oldsolid = pusher->v.solid; // non-solid pushers can't push anything if( pusher->v.solid == SOLID_NOT ) return NULL; // see if any solid entities are inside the final position num_moved = 0; for( e = 1; e < svgame.numEntities; e++ ) { check = EDICT_NUM( e ); if( !SV_IsValidEdict( check )) continue; // filter movetypes to collide with if( !SV_CanPushed( check )) continue; pusher->v.solid = SOLID_NOT; block = SV_TestEntityPosition( check, pusher ); pusher->v.solid = oldsolid; if( block ) continue; // if the entity is standing on the pusher, it will definately be moved if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher )) { if( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if( !SV_TestEntityPosition( check, NULL )) continue; } // remove the onground flag for non-players if( check->v.movetype != MOVETYPE_WALK ) check->v.flags &= ~FL_ONGROUND; // save original position of contacted entity pushed_p->ent = check; VectorCopy( check->v.origin, pushed_p->origin ); VectorCopy( check->v.angles, pushed_p->angles ); pushed_p++; // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity( check, lmove, vec3_origin, &block ); pusher->v.solid = oldsolid; // if it is still inside the pusher, block if( SV_TestEntityPosition( check, NULL ) && block ) { if( !SV_CanBlock( check )) continue; pusher->v.ltime -= movetime; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for( p = pushed_p - 1; p >= svgame.pushed; p-- ) { VectorCopy( p->origin, p->ent->v.origin ); VectorCopy( p->angles, p->ent->v.angles ); SV_LinkEdict( p->ent, (p->ent == check) ? true : false ); } return check; } } return NULL; }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; // 2001-09-20 Configurable entity limits by Maddes start /* edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; */ // 2001-09-20 Configurable entity limits by Maddes end float solid_backup; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } // 2001-09-20 Configurable entity limits by Maddes start // FIXME: is this really necessary memset (moved_edict, 0, sv.max_edicts*sizeof(edict_t *)); memset (moved_from, 0, sv.max_edicts*sizeof(vec3_t)); // 2001-09-20 Configurable entity limits by Maddes end for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start solid_backup = pusher->v.solid; if ( solid_backup == SOLID_BSP // everything that blocks: bsp models==map brushes==doors,plats,etc. || solid_backup == SOLID_BBOX // normally boxes || solid_backup == SOLID_SLIDEBOX ) // normally monsters { // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start // pusher->v.solid = SOLID_BSP; pusher->v.solid = solid_backup; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end // if it is still inside the pusher, block // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes start block = SV_TestEntityPosition (check); } else block = NULL; // 1999-10-07 MOVETYPE_PUSH fix by LordHavoc/Maddes end if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.origin); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }
/* ============ SV_Push Objects need to be moved back on a failed push, otherwise riders would continue to slide. ============ */ qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) { int i, e; edict_t *check, *block; pushed_t *p; vec3_t org, org2, move2, forward, right, up; vec3_t realmins, realmaxs; if (!pusher) { return false; } /* clamp the move to 1/8 units, so the position will be accurate for client side prediction */ for (i = 0; i < 3; i++) { float temp; temp = move[i] * 8.0; if (temp > 0.0) { temp += 0.5; } else { temp -= 0.5; } move[i] = 0.125 * (int)temp; } /* we need this for pushing things later */ VectorSubtract(vec3_origin, amove, org); AngleVectors(org, forward, right, up); /* save the pusher's original position */ pushed_p->ent = pusher; VectorCopy(pusher->s.origin, pushed_p->origin); VectorCopy(pusher->s.angles, pushed_p->angles); if (pusher->client) { pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; } pushed_p++; /* move the pusher to it's final position */ VectorAdd(pusher->s.origin, move, pusher->s.origin); VectorAdd(pusher->s.angles, amove, pusher->s.angles); gi.linkentity(pusher); /* Create a real bounding box for rotating brush models. */ SV_RealBoundingBox(pusher, realmins, realmaxs); /* see if any solid entities are inside the final position */ check = g_edicts + 1; for (e = 1; e < globals.num_edicts; e++, check++) { if (!check->inuse) { continue; } if ((check->movetype == MOVETYPE_PUSH) || (check->movetype == MOVETYPE_STOP) || (check->movetype == MOVETYPE_NONE) || (check->movetype == MOVETYPE_NOCLIP)) { continue; } if (!check->area.prev) { continue; /* not linked in anywhere */ } /* if the entity is standing on the pusher, it will definitely be moved */ if (check->groundentity != pusher) { /* see if the ent needs to be tested */ if ((check->absmin[0] >= realmaxs[0]) || (check->absmin[1] >= realmaxs[1]) || (check->absmin[2] >= realmaxs[2]) || (check->absmax[0] <= realmins[0]) || (check->absmax[1] <= realmins[1]) || (check->absmax[2] <= realmins[2])) { continue; } /* see if the ent's bbox is inside the pusher's final position */ if (!SV_TestEntityPosition(check)) { continue; } } if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher)) { // move this entity pushed_p->ent = check; VectorCopy (check->s.origin, pushed_p->origin); VectorCopy (check->s.angles, pushed_p->angles); pushed_p++; // try moving the contacted entity VectorAdd (check->s.origin, move, check->s.origin); if (check->client) { // FIXME: doesn't rotate monsters? check->client->ps.pmove.delta_angles[YAW] += amove[YAW]; } /* figure movement due to the pusher's amove */ VectorSubtract(check->s.origin, pusher->s.origin, org); org2[0] = DotProduct(org, forward); org2[1] = -DotProduct(org, right); /* Quirk for blocking Elevators when running under amd64. This is most likey caused by a too high float precision. -_- */ if (((pusher->s.number == 285) && (Q_strcasecmp(level.mapname, "xcompnd2") == 0)) || ((pusher->s.number == 520) && (Q_strcasecmp(level.mapname, "xsewer2") == 0))) { org2[2] = DotProduct(org, up) + 2; } else { org2[2] = DotProduct(org, up); } VectorSubtract(org2, org, move2); VectorAdd(check->s.origin, move2, check->s.origin); /* may have pushed them off an edge */ if (check->groundentity != pusher) { check->groundentity = NULL; } block = SV_TestEntityPosition (check); if (!block) { // pushed ok gi.linkentity (check); // impact? continue; } // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed // FIXME: this doesn't acount for rotation VectorSubtract (check->s.origin, move, check->s.origin); block = SV_TestEntityPosition (check); if (!block) { pushed_p--; continue; } } // save off the obstacle so we can call the block function obstacle = check; // move back any entities we already moved // go backwards, so if the same entity was pushed // twice, it goes back to the original position for (p=pushed_p-1 ; p>=pushed ; p--) { VectorCopy (p->origin, p->ent->s.origin); VectorCopy (p->angles, p->ent->s.angles); if (p->ent->client) { p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; } gi.linkentity (p->ent); } return false; } //FIXME: is there a better way to handle this? // see if anything we moved has touched a trigger for (p=pushed_p-1 ; p>=pushed ; p--) { G_TouchTriggers (p->ent); } return true; }
/* ============ SV_PushRotate ============ */ void SV_PushRotate (edict_t *pusher, float movetime) { int i, e, t, num_moved, slaves_moved; edict_t *check, *block, *ground, *master, *slave; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; vec3_t move, a, amove, mins, maxs, move2, move3, testmove; vec3_t entorig, pushorig, pushorigangles; vec3_t org, org2, check_center; vec3_t forward, right, up; qboolean moveit; for (i=0 ; i<3 ; i++) { amove[i] = pusher->v.avelocity[i] * movetime; move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorSubtract (vec3_origin, amove, a); AngleVectors (a, forward, right, up); VectorCopy (pusher->v.origin, pushorig); VectorCopy (pusher->v.angles, pushorigangles); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); VectorAdd (pusher->v.angles, amove, pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); master = pusher; slaves_moved = 0; // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definitely be moved moveit = false; ground = PROG_TO_EDICT(check->v.groundentity); if ((int)check->v.flags & FL_ONGROUND) { if (ground == pusher) { moveit = true; } else { for (i=0; i<slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { moveit = true; break; } } } } if (!moveit) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) { for (i=0; i<slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; if ( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) continue; } // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; //put check in first move spot VectorAdd (check->v.origin, move, check->v.origin); //Use center of model, like in QUAKE!!!! Our origins are on the bottom!!! for (i=0 ; i<3 ; i++) check_center[i] = (check->v.absmin[i] + check->v.absmax[i])/2; // calculate destination position VectorSubtract (check_center, pusher->v.origin, org); //put check back VectorSubtract (check->v.origin, move, check->v.origin); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move2); //Add all moves together VectorAdd(move,move2,move3); // try moving the contacted entity for( t = 0; t < 13; t++) { switch(t) { case 0: //try x, y and z VectorCopy(move3,testmove); break; case 1: //Try xy only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]; testmove[1]=move3[1]; testmove[2]=0; break; case 2: //Try z only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=move3[2]; break; case 3: //Try none VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=0; break; case 4: //Try xy in opposite dir testmove[0]=move3[0]*-1; testmove[1]=move3[1]*-1; testmove[2]=move3[2]; break; case 5: //Try z in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]; testmove[1]=move3[1]; testmove[2]=move3[2]*-1; break; case 6: //Try xyz in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=move3[0]*-1; testmove[1]=move3[1]*-1; testmove[2]=move3[2]*-1; break; case 7: //Try move3 times 2 VectorSubtract(check->v.origin,testmove,check->v.origin); VectorScale(move3,2,testmove); break; case 8: //Try normalized org VectorSubtract(check->v.origin,testmove,check->v.origin); VectorScale(org,movetime,org);//movetime*20? VectorCopy(org,testmove); break; case 9: //Try normalized org z * 3 only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=0; testmove[1]=0; testmove[2]=org[2]*3;//was: +org[2]*(fastfabs(org[1])+fastfabs(org[2])); break; case 10: //Try normalized org xy * 2 only VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]*2;//was: +org[0]*fastfabs(org[2]); testmove[1]=org[1]*2;//was: +org[1]*fastfabs(org[2]); testmove[2]=0; break; case 11: //Try xy in opposite org dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]*-2; testmove[1]=org[1]*-2; testmove[2]=org[2]; break; case 12: //Try z in opposite dir VectorSubtract(check->v.origin,testmove,check->v.origin); testmove[0]=org[0]; testmove[1]=org[1]; testmove[2]=org[2]*-3; break; } if(t!=3) { //THIS IS VERY BAD BAD HACK... pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move3); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? // if (!((int)check->v.flags & (FL_CLIENT | FL_MONSTER))) // VectorAdd (check->v.angles, amove, check->v.angles); check->v.angles[YAW] += amove[YAW]; pusher->v.solid = SOLID_BSP; } // if it is still inside the pusher, block block = SV_TestEntityPosition (check); if(!block) break; } if (block) { // fail the move // Con_DPrintf("Check blocked\n"); if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.origin); VectorCopy (pushorigangles, pusher->v.angles); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; for (i=0; i<slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; VectorCopy (moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict (slave, false); slave->v.ltime -= movetime; } // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { *pr_global_ptrs.self = EDICT_TO_PROG(pusher); *pr_global_ptrs.other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) // VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict (moved_edict[i], false); } return; } } }
/* ============ SV_PushMove ============ */ void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t *moved_edict[MAX_EDICTS]; vec3_t moved_from[MAX_EDICTS]; if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position num_moved = 0; check = NEXT_EDICT(sv.edicts); for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) { if (check->free) continue; if (check->v.movetype == MOVETYPE_PUSH || check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW // Nehahra || check->v.movetype == MOVETYPE_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if ( ! ( ((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher) ) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[2] ) continue; // see if the ent's bbox is inside the pusher's final position if (!SV_TestEntityPosition (check)) continue; } // remove the onground flag for non-players if (check->v.movetype != MOVETYPE_WALK) check->v.flags = (int)check->v.flags & ~FL_ONGROUND; VectorCopy (check->v.origin, entorig); VectorCopy (check->v.origin, moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // only check for types that can block if (pusher->v.solid == SOLID_BSP // everything that blocks: bsp models, map brushes, doors, plats etc. || pusher->v.solid == SOLID_BBOX // normally boxes || pusher->v.solid == SOLID_SLIDEBOX) // normally monsters { // store out the previous solid value because we're going to change it next float savepushervsolid = pusher->v.solid; // try moving the contacted entity pusher->v.solid = SOLID_NOT; SV_PushEntity (check, move); // restore from the stored solid pusher->v.solid = savepushervsolid; // if it is still inside the pusher, block block = SV_TestEntityPosition (check); } else { // not blocked block = NULL; } if (block) { // fail the move if (check->v.mins[0] == check->v.maxs[0]) continue; if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; VectorCopy (check->v.mins, check->v.maxs); continue; } VectorCopy (entorig, check->v.origin); SV_LinkEdict (check, true); VectorCopy (pushorig, pusher->v.origin); SV_LinkEdict (pusher, false); pusher->v.ltime -= movetime; // if the pusher has a "blocked" function, call it // otherwise, just stay in place until the obstacle is gone if (pusher->v.blocked) { pr_global_struct->self = EDICT_TO_PROG(pusher); pr_global_struct->other = EDICT_TO_PROG(check); PR_ExecuteProgram (pusher->v.blocked); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { VectorCopy (moved_from[i], moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } return; } } }