/* ============ G_MoverPush Objects need to be moved back on a failed push, otherwise riders would continue to slide. If qfalse is returned, *obstacle will be the blocking entity ============ */ qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t **obstacle ) { int i, e; gentity_t *check; vec3_t mins, maxs; pushed_t *p; int entityList[MAX_GENTITIES]; int listedEntities; vec3_t totalMins, totalMaxs; *obstacle = NULL; // mins/maxs are the bounds at the destination // totalMins / totalMaxs are the bounds for the entire move if ( pusher->r.currentAngles[0] || pusher->r.currentAngles[1] || pusher->r.currentAngles[2] || amove[0] || amove[1] || amove[2] ) { float radius; radius = RadiusFromBounds( pusher->r.mins, pusher->r.maxs ); for ( i = 0 ; i < 3 ; i++ ) { mins[i] = pusher->r.currentOrigin[i] + move[i] - radius; maxs[i] = pusher->r.currentOrigin[i] + move[i] + radius; totalMins[i] = mins[i] - move[i]; totalMaxs[i] = maxs[i] - move[i]; } } else { for (i=0 ; i<3 ; i++) { mins[i] = pusher->r.absmin[i] + move[i]; maxs[i] = pusher->r.absmax[i] + move[i]; } VectorCopy( pusher->r.absmin, totalMins ); VectorCopy( pusher->r.absmax, totalMaxs ); for (i=0 ; i<3 ; i++) { if ( move[i] > 0 ) { totalMaxs[i] += move[i]; } else { totalMins[i] += move[i]; } } } // unlink the pusher so we don't get it in the entityList trap_UnlinkEntity( pusher ); listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES ); // move the pusher to it's final position VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin ); VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles ); trap_LinkEntity( pusher ); // see if any solid entities are inside the final position for ( e = 0 ; e < listedEntities ; e++ ) { check = &g_entities[ entityList[ e ] ]; #ifdef MISSIONPACK if ( check->s.eType == ET_MISSILE ) { // if it is a prox mine if ( !strcmp(check->classname, "prox mine") ) { // if this prox mine is attached to this mover try to move it with the pusher if ( check->enemy == pusher ) { if (!G_TryPushingProxMine( check, pusher, move, amove )) { //explode check->s.loopSound = 0; G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 ); G_ExplodeMissile(check); if (check->activator) { G_FreeEntity(check->activator); check->activator = NULL; } //G_Printf("prox mine explodes\n"); } } else { //check if the prox mine is crushed by the mover if (!G_CheckProxMinePosition( check )) { //explode check->s.loopSound = 0; G_AddEvent( check, EV_PROXIMITY_MINE_TRIGGER, 0 ); G_ExplodeMissile(check); if (check->activator) { G_FreeEntity(check->activator); check->activator = NULL; } //G_Printf("prox mine explodes\n"); } } continue; } } #endif // only push items and players if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) { continue; } // if the entity is standing on the pusher, it will definitely be moved if ( check->s.groundEntityNum != pusher->s.number ) { // 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 // this does allow a fast moving object to pass through a thin entity... if (!G_TestEntityPosition (check)) { continue; } } // the entity needs to be pushed if ( G_TryPushingEntity( check, pusher, move, amove ) ) { continue; } // the move was blocked an entity // bobbing entities are instant-kill and never get blocked if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) { G_Damage( check, pusher, pusher, NULL, NULL, 99999, 0, MOD_CRUSH ); continue; } // save off the obstacle so we can call the block function (crush, etc) *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.pos.trBase); VectorCopy (p->angles, p->ent->s.apos.trBase); if ( p->ent->client ) { p->ent->client->ps.delta_angles[YAW] = p->deltayaw; VectorCopy (p->origin, p->ent->client->ps.origin); } trap_LinkEntity (p->ent); } return qfalse; } return qtrue; }
// Objects need to be moved back on a failed push, otherwise riders would continue to slide. // If qfalse is returned, *obstacle will be the blocking entity qboolean G_MoverPush( gentity_t *pusher, vector3 *move, vector3 *amove, gentity_t **obstacle ) { int i, e; gentity_t *check; vector3 mins, maxs; pushed_t *p; int entityList[MAX_GENTITIES]; int listedEntities; vector3 totalMins, totalMaxs; *obstacle = NULL; // mins/maxs are the bounds at the destination // totalMins / totalMaxs are the bounds for the entire move if ( pusher->r.currentAngles.x || pusher->r.currentAngles.y || pusher->r.currentAngles.z || amove->x || amove->y || amove->z ) { float radius; radius = RadiusFromBounds( &pusher->r.mins, &pusher->r.maxs ); for ( i = 0 ; i < 3 ; i++ ) { mins.data[i] = pusher->r.currentOrigin.data[i] + move->data[i] - radius; maxs.data[i] = pusher->r.currentOrigin.data[i] + move->data[i] + radius; totalMins.data[i] = mins.data[i] - move->data[i]; totalMaxs.data[i] = maxs.data[i] - move->data[i]; } } else { for (i=0 ; i<3 ; i++) { mins.data[i] = pusher->r.absmin.data[i] + move->data[i]; maxs.data[i] = pusher->r.absmax.data[i] + move->data[i]; } VectorCopy( &pusher->r.absmin, &totalMins ); VectorCopy( &pusher->r.absmax, &totalMaxs ); for (i=0 ; i<3 ; i++) { if ( move->data[i] > 0 ) totalMaxs.data[i] += move->data[i]; else totalMins.data[i] += move->data[i]; } } // unlink the pusher so we don't get it in the entityList trap->SV_UnlinkEntity( (sharedEntity_t *)pusher ); listedEntities = trap->SV_AreaEntities( &totalMins, &totalMaxs, entityList, MAX_GENTITIES ); // move the pusher to its final position VectorAdd( &pusher->r.currentOrigin, move, &pusher->r.currentOrigin ); VectorAdd( &pusher->r.currentAngles, amove, &pusher->r.currentAngles ); trap->SV_LinkEntity( (sharedEntity_t *)pusher ); // see if any solid entities are inside the final position for ( e = 0 ; e < listedEntities ; e++ ) { check = &g_entities[ entityList[ e ] ]; // only push items and players if ( check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) { continue; } // if the entity is standing on the pusher, it will definitely be moved if ( check->s.groundEntityNum != pusher->s.number ) { // see if the ent needs to be tested if ( check->r.absmin.x >= maxs.x || check->r.absmin.y >= maxs.y || check->r.absmin.z >= maxs.z || check->r.absmax.x <= mins.x || check->r.absmax.y <= mins.y || check->r.absmax.z <= mins.z ) { continue; } // see if the ent's bbox is inside the pusher's final position // this does allow a fast moving object to pass through a thin entity... if (!G_TestEntityPosition (check)) { continue; } } // the entity needs to be pushed if ( G_TryPushingEntity( check, pusher, move, amove ) ) { continue; } // the move was blocked an entity // bobbing entities are instant-kill and never get blocked if ( pusher->s.pos.trType == TR_SINE || pusher->s.apos.trType == TR_SINE ) { //Raz: don't care about the affector for pushers G_Damage( check, pusher, pusher, NULL, NULL, NULL, 99999, 0, MOD_CRUSH ); continue; } // save off the obstacle so we can call the block function (crush, etc) *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.pos.trBase); VectorCopy (&p->angles, &p->ent->s.apos.trBase); if ( p->ent->client ) { p->ent->client->ps.delta_angles.yaw = (int)p->deltayaw; VectorCopy (&p->origin, &p->ent->client->ps.origin); } trap->SV_LinkEntity ((sharedEntity_t *)p->ent); } return qfalse; } return qtrue; }