diff options
Diffstat (limited to 'src/game/g_mover.c')
-rw-r--r-- | src/game/g_mover.c | 453 |
1 files changed, 265 insertions, 188 deletions
diff --git a/src/game/g_mover.c b/src/game/g_mover.c index 20b5c08..77c1e0c 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -1,13 +1,14 @@ /* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus +Copyright (C) 2000-2013 Darklegion Development +Copyright (C) 2015-2019 GrangerHub This file is part of Tremulous. Tremulous is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, +published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Tremulous is distributed in the hope that it will be @@ -16,8 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +along with Tremulous; if not, see <https://www.gnu.org/licenses/> + =========================================================================== */ @@ -33,8 +34,6 @@ PUSHMOVE =============================================================================== */ -void MatchTeam( gentity_t *teamLeader, int moverState, int time ); - typedef struct { gentity_t *ent; @@ -55,17 +54,11 @@ G_TestEntityPosition gentity_t *G_TestEntityPosition( gentity_t *ent ) { trace_t tr; - int mask; - - if( ent->clipmask ) - mask = ent->clipmask; - else - mask = MASK_SOLID; if( ent->client ) - trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask ); + trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, ent->clipmask ); else - trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask ); + trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, ent->clipmask ); if( tr.startsolid ) return &g_entities[ tr.entityNum ]; @@ -183,7 +176,7 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v // may have pushed them off an edge if( check->s.groundEntityNum != pusher->s.number ) - check->s.groundEntityNum = -1; + check->s.groundEntityNum = ENTITYNUM_NONE; block = G_TestEntityPosition( check ); @@ -212,7 +205,7 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v if( !block ) { - check->s.groundEntityNum = -1; + check->s.groundEntityNum = ENTITYNUM_NONE; pushed_p--; return qtrue; } @@ -285,7 +278,7 @@ qboolean G_MoverPush( gentity_t *pusher, vec3_t move, vec3_t amove, gentity_t ** listedEntities = trap_EntitiesInBox( totalMins, totalMaxs, entityList, MAX_GENTITIES ); - // move the pusher to it's final position + // move the pusher to its final position VectorAdd( pusher->r.currentOrigin, move, pusher->r.currentOrigin ); VectorAdd( pusher->r.currentAngles, amove, pusher->r.currentAngles ); trap_LinkEntity( pusher ); @@ -379,6 +372,12 @@ void G_MoverTeam( gentity_t *ent ) pushed_p = pushed; for( part = ent; part; part = part->teamchain ) { + if( part->s.pos.trType == TR_STATIONARY && + part->s.apos.trType == TR_STATIONARY ) + { + continue; + } + // get current position BG_EvaluateTrajectory( &part->s.pos, level.time, origin ); BG_EvaluateTrajectory( &part->s.apos, level.time, angles ); @@ -393,6 +392,12 @@ void G_MoverTeam( gentity_t *ent ) // go back to the previous position for( part = ent; part; part = part->teamchain ) { + if( part->s.pos.trType == TR_STATIONARY && + part->s.apos.trType == TR_STATIONARY ) + { + continue; + } + part->s.pos.trTime += level.time - level.previousTime; part->s.apos.trTime += level.time - level.previousTime; BG_EvaluateTrajectory( &part->s.pos, level.time, part->r.currentOrigin ); @@ -442,10 +447,7 @@ void G_RunMover( gentity_t *ent ) if( ent->flags & FL_TEAMSLAVE ) return; - // if stationary at one of the positions, don't move anything - if( ( ent->s.pos.trType != TR_STATIONARY || ent->s.apos.trType != TR_STATIONARY ) && - ent->moverState < MODEL_POS1 ) //yuck yuck hack - G_MoverTeam( ent ); + G_MoverTeam( ent ); // check think function G_RunThink( ent ); @@ -554,7 +556,6 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) MatchTeam All entities in a mover team will move from pos1 to pos2 -in the same amount of time ================ */ void MatchTeam( gentity_t *teamLeader, int moverState, int time ) @@ -566,40 +567,65 @@ void MatchTeam( gentity_t *teamLeader, int moverState, int time ) } +/* +================ +MasterOf +================ +*/ +gentity_t *MasterOf( gentity_t *ent ) +{ + if( ent->teammaster ) + return ent->teammaster; + else + return ent; +} + /* ================ -ReturnToPos1 +GetMoverTeamState + +Returns a MOVER_* value representing the phase (either one + of pos1, 1to2, pos2, or 2to1) of a mover team as a whole. ================ */ -void ReturnToPos1( gentity_t *ent ) +moverState_t GetMoverTeamState( gentity_t *ent ) { - MatchTeam( ent, MOVER_2TO1, level.time ); + qboolean pos1 = qfalse; - // looping sound - ent->s.loopSound = ent->soundLoop; + for( ent = MasterOf( ent ); ent; ent = ent->teamchain ) + { + if( ent->moverState == MOVER_POS1 || ent->moverState == ROTATOR_POS1 ) + pos1 = qtrue; + else if( ent->moverState == MOVER_1TO2 || ent->moverState == ROTATOR_1TO2 ) + return MOVER_1TO2; + else if( ent->moverState == MOVER_2TO1 || ent->moverState == ROTATOR_2TO1 ) + return MOVER_2TO1; + } - // starting sound - if( ent->sound2to1 ) - G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); + if( pos1 ) + return MOVER_POS1; + else + return MOVER_POS2; } /* ================ -ReturnToApos1 +ReturnToPos1orApos1 + +Used only by a master movers. ================ */ -void ReturnToApos1( gentity_t *ent ) -{ - MatchTeam( ent, ROTATOR_2TO1, level.time ); - // looping sound - ent->s.loopSound = ent->soundLoop; +void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ); - // starting sound - if( ent->sound2to1 ) - G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); +void ReturnToPos1orApos1( gentity_t *ent ) +{ + if( GetMoverTeamState( ent ) != MOVER_POS2 ) + return; // not every mover in the team has reached its endpoint yet + + Use_BinaryMover( ent, ent, ent->activator ); } @@ -690,10 +716,10 @@ void Think_OpenModelDoor( gentity_t *ent ) //set brush non-solid trap_UnlinkEntity( ent->clipBrush ); - // looping sound - ent->s.loopSound = ent->soundLoop; + // stop the looping sound + ent->s.loopSound = 0; - // starting sound + // play sound if( ent->soundPos2 ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 ); @@ -718,8 +744,10 @@ Reached_BinaryMover */ void Reached_BinaryMover( gentity_t *ent ) { + gentity_t *master = MasterOf( ent ); + // stop the looping sound - ent->s.loopSound = ent->soundLoop; + ent->s.loopSound = 0; if( ent->moverState == MOVER_1TO2 ) { @@ -731,8 +759,8 @@ void Reached_BinaryMover( gentity_t *ent ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 ); // return to pos1 after a delay - ent->think = ReturnToPos1; - ent->nextthink = level.time + ent->wait; + master->think = ReturnToPos1orApos1; + master->nextthink = MAX( master->nextthink, level.time + ent->wait ); // fire targets if( !ent->activator ) @@ -763,8 +791,8 @@ void Reached_BinaryMover( gentity_t *ent ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 ); // return to apos1 after a delay - ent->think = ReturnToApos1; - ent->nextthink = level.time + ent->wait; + master->think = ReturnToPos1orApos1; + master->nextthink = MAX( master->nextthink, level.time + ent->wait ); // fire targets if( !ent->activator ) @@ -799,6 +827,8 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) { int total; int partial; + gentity_t *master; + moverState_t teamState; // if this is a non-client-usable door return if( ent->targetname && other && other->client ) @@ -813,11 +843,17 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) ent->activator = activator; + master = MasterOf( ent ); + teamState = GetMoverTeamState( ent ); + + for( ent = master; ent; ent = ent->teamchain ) + { + //ind if( ent->moverState == MOVER_POS1 ) { // start moving 50 msec later, becase if this was player // triggered, level.time hasn't been advanced yet - MatchTeam( ent, MOVER_1TO2, level.time + 50 ); + SetMoverState( ent, MOVER_1TO2, level.time + 50 ); // starting sound if( ent->sound1to2 ) @@ -830,10 +866,30 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( ent->teammaster == ent || !ent->teammaster ) trap_AdjustAreaPortalState( ent, qtrue ); } - else if( ent->moverState == MOVER_POS2 ) + else if( ent->moverState == MOVER_POS2 && + !( teamState == MOVER_1TO2 || other == master ) ) { // if all the way up, just delay before coming down - ent->nextthink = level.time + ent->wait; + master->think = ReturnToPos1orApos1; + master->nextthink = MAX( master->nextthink, level.time + ent->wait ); + } + else if( ent->moverState == MOVER_POS2 && + ( teamState == MOVER_1TO2 || other == master ) ) + { + // start moving 50 msec later, becase if this was player + // triggered, level.time hasn't been advanced yet + SetMoverState( ent, MOVER_2TO1, level.time + 50 ); + + // starting sound + if( ent->sound2to1 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); + + // looping sound + ent->s.loopSound = ent->soundLoop; + + // open areaportal + if( ent->teammaster == ent || !ent->teammaster ) + trap_AdjustAreaPortalState( ent, qtrue ); } else if( ent->moverState == MOVER_2TO1 ) { @@ -844,7 +900,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( partial > total ) partial = total; - MatchTeam( ent, MOVER_1TO2, level.time - ( total - partial ) ); + SetMoverState( ent, MOVER_1TO2, level.time - ( total - partial ) ); if( ent->sound1to2 ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 ); @@ -858,7 +914,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( partial > total ) partial = total; - MatchTeam( ent, MOVER_2TO1, level.time - ( total - partial ) ); + SetMoverState( ent, MOVER_2TO1, level.time - ( total - partial ) ); if( ent->sound2to1 ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); @@ -867,7 +923,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) { // start moving 50 msec later, becase if this was player // triggered, level.time hasn't been advanced yet - MatchTeam( ent, ROTATOR_1TO2, level.time + 50 ); + SetMoverState( ent, ROTATOR_1TO2, level.time + 50 ); // starting sound if( ent->sound1to2 ) @@ -880,10 +936,30 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( ent->teammaster == ent || !ent->teammaster ) trap_AdjustAreaPortalState( ent, qtrue ); } - else if( ent->moverState == ROTATOR_POS2 ) + else if( ent->moverState == ROTATOR_POS2 && + !( teamState == MOVER_1TO2 || other == master ) ) { // if all the way up, just delay before coming down - ent->nextthink = level.time + ent->wait; + master->think = ReturnToPos1orApos1; + master->nextthink = MAX( master->nextthink, level.time + ent->wait ); + } + else if( ent->moverState == ROTATOR_POS2 && + ( teamState == MOVER_1TO2 || other == master ) ) + { + // start moving 50 msec later, becase if this was player + // triggered, level.time hasn't been advanced yet + SetMoverState( ent, ROTATOR_2TO1, level.time + 50 ); + + // starting sound + if( ent->sound2to1 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); + + // looping sound + ent->s.loopSound = ent->soundLoop; + + // open areaportal + if( ent->teammaster == ent || !ent->teammaster ) + trap_AdjustAreaPortalState( ent, qtrue ); } else if( ent->moverState == ROTATOR_2TO1 ) { @@ -894,7 +970,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( partial > total ) partial = total; - MatchTeam( ent, ROTATOR_1TO2, level.time - ( total - partial ) ); + SetMoverState( ent, ROTATOR_1TO2, level.time - ( total - partial ) ); if( ent->sound1to2 ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 ); @@ -908,7 +984,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) if( partial > total ) partial = total; - MatchTeam( ent, ROTATOR_2TO1, level.time - ( total - partial ) ); + SetMoverState( ent, ROTATOR_2TO1, level.time - ( total - partial ) ); if( ent->sound2to1 ) G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); @@ -939,6 +1015,8 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) // if all the way up, just delay before coming down ent->nextthink = level.time + ent->wait; } + //outd + } } @@ -959,15 +1037,16 @@ void InitMover( gentity_t *ent ) vec3_t color; qboolean lightSet, colorSet; char *sound; + char *team; // if the "model2" key is set, use a seperate model // for drawing, but clip against the brushes if( ent->model2 ) ent->s.modelindex2 = G_ModelIndex( ent->model2 ); - // if the "loopsound" key is set, use a constant looping sound when moving - if( G_SpawnString( "noise", "100", &sound ) ) - ent->s.loopSound = G_SoundIndex( sound ); + // if the "noise" key is set, use a constant looping sound when moving + if( G_SpawnString( "noise", "", &sound ) ) + ent->soundLoop = G_SoundIndex( sound ); // if the "color" or "light" keys are set, setup constantLight lightSet = G_SpawnFloat( "light", "100", &light ); @@ -1000,8 +1079,10 @@ void InitMover( gentity_t *ent ) ent->use = Use_BinaryMover; ent->reached = Reached_BinaryMover; + if( G_SpawnString( "team", "", &team ) ) + ent->team = G_CopyString( team ); + ent->moverState = MOVER_POS1; - ent->r.svFlags = SVF_USE_CURRENT_ORIGIN; ent->s.eType = ET_MOVER; VectorCopy( ent->pos1, ent->r.currentOrigin ); trap_LinkEntity( ent ); @@ -1039,15 +1120,16 @@ void InitRotator( gentity_t *ent ) vec3_t color; qboolean lightSet, colorSet; char *sound; + char *team; // if the "model2" key is set, use a seperate model // for drawing, but clip against the brushes if( ent->model2 ) ent->s.modelindex2 = G_ModelIndex( ent->model2 ); - // if the "loopsound" key is set, use a constant looping sound when moving - if( G_SpawnString( "noise", "100", &sound ) ) - ent->s.loopSound = G_SoundIndex( sound ); + // if the "noise" key is set, use a constant looping sound when moving + if( G_SpawnString( "noise", "", &sound ) ) + ent->soundLoop = G_SoundIndex( sound ); // if the "color" or "light" keys are set, setup constantLight lightSet = G_SpawnFloat( "light", "100", &light ); @@ -1084,8 +1166,10 @@ void InitRotator( gentity_t *ent ) ent->use = Use_BinaryMover; ent->reached = Reached_BinaryMover; + if( G_SpawnString( "team", "", &team ) ) + ent->team = G_CopyString( team ); + ent->moverState = ROTATOR_POS1; - ent->r.svFlags = SVF_USE_CURRENT_ORIGIN; ent->s.eType = ET_MOVER; VectorCopy( ent->pos1, ent->r.currentAngles ); trap_LinkEntity( ent ); @@ -1156,8 +1240,8 @@ static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_ axis = ent->count; VectorClear( dir ); - if( fabs( other->s.origin[ axis ] - ent->r.absmax[ axis ] ) < - fabs( other->s.origin[ axis ] - ent->r.absmin[ axis ] ) ) + if( fabs( other->r.currentOrigin[ axis ] - ent->r.absmax[ axis ] ) < + fabs( other->r.currentOrigin[ axis ] - ent->r.absmin[ axis ] ) ) { origin[ axis ] = ent->r.absmin[ axis ] - 20; dir[ axis ] = -1; @@ -1177,7 +1261,7 @@ static void Touch_DoorTriggerSpectator( gentity_t *ent, gentity_t *other, trace_ } vectoangles( dir, angles ); - TeleportPlayer( other, origin, angles ); + TeleportPlayer( other, origin, angles, 400.0f ); } @@ -1237,7 +1321,7 @@ static void manualDoorTriggerSpectator( gentity_t *door, gentity_t *player ) ================ manualTriggerSpectator -Trip to skip the closest door targetted by trigger +Trip to skip the closest door targeted by trigger ================ */ void manualTriggerSpectator( gentity_t *trigger, gentity_t *player ) @@ -1259,14 +1343,6 @@ void manualTriggerSpectator( gentity_t *trigger, gentity_t *player ) { if( !strcmp( t->classname, "func_door" ) ) targets[ i++ ] = t; - else if( t == trigger ) - G_Printf( "WARNING: Entity used itself.\n" ); - - if( !trigger->inuse ) - { - G_Printf( "triggerity was removed while using targets\n" ); - return; - } } //if more than 0 targets @@ -1299,25 +1375,30 @@ Touch_DoorTrigger */ void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) { + moverState_t teamState; + //buildables don't trigger movers if( other->s.eType == ET_BUILDABLE ) return; - if( other->client && other->client->sess.sessionTeam == TEAM_SPECTATOR ) + teamState = GetMoverTeamState( ent->parent ); + + if( other->client && other->client->sess.spectatorState != SPECTATOR_NOT ) { // if the door is not open and not opening - if( ent->parent->moverState != MOVER_1TO2 && - ent->parent->moverState != MOVER_POS2 && - ent->parent->moverState != ROTATOR_1TO2 && - ent->parent->moverState != ROTATOR_POS2 ) + if( teamState != MOVER_POS2 && teamState != MOVER_1TO2 ) Touch_DoorTriggerSpectator( ent, other, trace ); } - else if( ent->parent->moverState != MOVER_1TO2 && - ent->parent->moverState != ROTATOR_1TO2 && - ent->parent->moverState != ROTATOR_2TO1 ) - { + else if( teamState != MOVER_1TO2 ) Use_BinaryMover( ent->parent, ent, other ); - } +} + + +void Think_MatchTeam( gentity_t *ent ) +{ + if( ent->flags & FL_TEAMSLAVE ) + return; + MatchTeam( ent, ent->moverState, level.time ); } @@ -1335,11 +1416,6 @@ void Think_SpawnNewDoorTrigger( gentity_t *ent ) vec3_t mins, maxs; int i, best; - //TA: disable shootable doors - // set all of the slaves as shootable - //for( other = ent; other; other = other->teamchain ) - // other->takedamage = qtrue; - // find the bounds of everything on the team VectorCopy( ent->r.absmin, mins ); VectorCopy( ent->r.absmax, maxs ); @@ -1374,12 +1450,7 @@ void Think_SpawnNewDoorTrigger( gentity_t *ent ) trap_LinkEntity( other ); if( ent->moverState < MODEL_POS1 ) - MatchTeam( ent, ent->moverState, level.time ); -} - -void Think_MatchTeam( gentity_t *ent ) -{ - MatchTeam( ent, ent->moverState, level.time ); + Think_MatchTeam( ent ); } @@ -1406,6 +1477,7 @@ void SP_func_door( gentity_t *ent ) vec3_t size; float lip; char *s; + int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1436,11 +1508,13 @@ void SP_func_door( gentity_t *ent ) G_SpawnInt( "dmg", "2", &ent->damage ); // first position at start - VectorCopy( ent->s.origin, ent->pos1 ); + VectorCopy( ent->r.currentOrigin, ent->pos1 ); + G_SetMovedir( ent->r.currentAngles, ent->movedir ); + VectorClear( ent->s.apos.trBase ); + VectorClear( ent->r.currentOrigin ); // calculate second position trap_SetBrushModel( ent, ent->model ); - G_SetMovedir( ent->s.angles, ent->movedir ); abs_movedir[ 0 ] = fabs( ent->movedir[ 0 ] ); abs_movedir[ 1 ] = fabs( ent->movedir[ 1 ] ); abs_movedir[ 2 ] = fabs( ent->movedir[ 2 ] ); @@ -1454,7 +1528,7 @@ void SP_func_door( gentity_t *ent ) vec3_t temp; VectorCopy( ent->pos2, temp ); - VectorCopy( ent->s.origin, ent->pos2 ); + VectorCopy( ent->r.currentOrigin, ent->pos2 ); VectorCopy( temp, ent->pos1 ); } @@ -1462,22 +1536,17 @@ void SP_func_door( gentity_t *ent ) ent->nextthink = level.time + FRAMETIME; - if( !( ent->flags & FL_TEAMSLAVE ) ) - { - int health; - - G_SpawnInt( "health", "0", &health ); - if( health ) - ent->takedamage = qtrue; + G_SpawnInt( "health", "0", &health ); + if( health ) + ent->takedamage = qtrue; - if( ent->targetname || health ) - { - // non touch/shoot doors - ent->think = Think_MatchTeam; - } - else - ent->think = Think_SpawnNewDoorTrigger; + if( ent->targetname || health ) + { + // non touch/shoot doors + ent->think = Think_MatchTeam; } + else + ent->think = Think_SpawnNewDoorTrigger; } /*QUAKED func_door_rotating (0 .5 .8) START_OPEN CRUSHER REVERSE TOGGLE X_AXIS Y_AXIS @@ -1502,6 +1571,7 @@ void SP_func_door( gentity_t *ent ) void SP_func_door_rotating( gentity_t *ent ) { char *s; + int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1534,7 +1604,8 @@ void SP_func_door_rotating( gentity_t *ent ) // set the axis of rotation VectorClear( ent->movedir ); - VectorClear( ent->s.angles ); + VectorClear( ent->s.apos.trBase ); + VectorClear( ent->r.currentAngles ); if( ent->spawnflags & 32 ) ent->movedir[ 2 ] = 1.0; @@ -1552,12 +1623,12 @@ void SP_func_door_rotating( gentity_t *ent ) if( !ent->rotatorAngle ) { G_Printf( "%s at %s with no rotatorAngle set.\n", - ent->classname, vtos( ent->s.origin ) ); + ent->classname, vtos( ent->r.currentOrigin ) ); ent->rotatorAngle = 90.0; } - VectorCopy( ent->s.angles, ent->pos1 ); + VectorCopy( ent->r.currentAngles, ent->pos1 ); trap_SetBrushModel( ent, ent->model ); VectorMA( ent->pos1, ent->rotatorAngle, ent->movedir, ent->pos2 ); @@ -1567,36 +1638,26 @@ void SP_func_door_rotating( gentity_t *ent ) vec3_t temp; VectorCopy( ent->pos2, temp ); - VectorCopy( ent->s.angles, ent->pos2 ); + VectorCopy( ent->pos1, ent->pos2 ); VectorCopy( temp, ent->pos1 ); VectorNegate( ent->movedir, ent->movedir ); } - // set origin - VectorCopy( ent->s.origin, ent->s.pos.trBase ); - VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); - InitRotator( ent ); ent->nextthink = level.time + FRAMETIME; - if( !( ent->flags & FL_TEAMSLAVE ) ) - { - int health; - - G_SpawnInt( "health", "0", &health ); - - if( health ) - ent->takedamage = qtrue; + G_SpawnInt( "health", "0", &health ); + if( health ) + ent->takedamage = qtrue; - if( ent->targetname || health ) - { - // non touch/shoot doors - ent->think = Think_MatchTeam; - } - else - ent->think = Think_SpawnNewDoorTrigger; + if( ent->targetname || health ) + { + // non touch/shoot doors + ent->think = Think_MatchTeam; } + else + ent->think = Think_SpawnNewDoorTrigger; } /*QUAKED func_door_model (0 .5 .8) ? START_OPEN @@ -1620,6 +1681,7 @@ void SP_func_door_model( gentity_t *ent ) qboolean lightSet, colorSet; char *sound; gentity_t *clipBrush; + int health; G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); ent->sound2to1 = G_SoundIndex( s ); @@ -1643,6 +1705,8 @@ void SP_func_door_model( gentity_t *ent ) //brush model clipBrush = ent->clipBrush = G_Spawn( ); + clipBrush->classname = "func_door_model_clip_brush"; + clipBrush->clipBrush = ent; // link back clipBrush->model = ent->model; trap_SetBrushModel( clipBrush, clipBrush->model ); clipBrush->s.eType = ET_INVISIBLE; @@ -1655,7 +1719,7 @@ void SP_func_door_model( gentity_t *ent ) VectorCopy( clipBrush->r.mins, ent->r.mins ); VectorCopy( clipBrush->r.maxs, ent->r.maxs ); - G_SpawnVector( "modelOrigin", "0 0 0", ent->s.origin ); + G_SpawnVector( "modelOrigin", "0 0 0", ent->r.currentOrigin ); G_SpawnVector( "scale", "1 1 1", ent->s.origin2 ); @@ -1666,9 +1730,9 @@ void SP_func_door_model( gentity_t *ent ) else ent->s.modelindex = G_ModelIndex( ent->model2 ); - // if the "loopsound" key is set, use a constant looping sound when moving - if( G_SpawnString( "noise", "100", &sound ) ) - ent->s.loopSound = G_SoundIndex( sound ); + // if the "noise" key is set, use a constant looping sound when moving + if( G_SpawnString( "noise", "", &sound ) ) + ent->soundLoop = G_SoundIndex( sound ); // if the "color" or "light" keys are set, setup constantLight lightSet = G_SpawnFloat( "light", "100", &light ); @@ -1701,19 +1765,17 @@ void SP_func_door_model( gentity_t *ent ) ent->moverState = MODEL_POS1; ent->s.eType = ET_MODELDOOR; - VectorCopy( ent->s.origin, ent->s.pos.trBase ); ent->s.pos.trType = TR_STATIONARY; ent->s.pos.trTime = 0; ent->s.pos.trDuration = 0; VectorClear( ent->s.pos.trDelta ); - VectorCopy( ent->s.angles, ent->s.apos.trBase ); ent->s.apos.trType = TR_STATIONARY; ent->s.apos.trTime = 0; ent->s.apos.trDuration = 0; VectorClear( ent->s.apos.trDelta ); - ent->s.misc = (int)ent->animation[ 0 ]; //first frame - ent->s.weapon = abs( (int)ent->animation[ 1 ] ); //number of frames + ent->s.misc = (int)ent->animation[ 0 ]; //first frame + ent->s.weapon = abs( (int)ent->animation[ 1 ] ); //number of frames //must be at least one frame -- mapper has forgotten animation key if( ent->s.weapon == 0 ) @@ -1723,19 +1785,14 @@ void SP_func_door_model( gentity_t *ent ) trap_LinkEntity( ent ); - if( !( ent->flags & FL_TEAMSLAVE ) ) - { - int health; - - G_SpawnInt( "health", "0", &health ); - if( health ) - ent->takedamage = qtrue; + G_SpawnInt( "health", "0", &health ); + if( health ) + ent->takedamage = qtrue; - if( !( ent->targetname || health ) ) - { - ent->nextthink = level.time + FRAMETIME; - ent->think = Think_SpawnNewDoorTrigger; - } + if( !( ent->targetname || health ) ) + { + ent->nextthink = level.time + FRAMETIME; + ent->think = Think_SpawnNewDoorTrigger; } } @@ -1751,7 +1808,7 @@ PLAT ============== Touch_Plat -Don't allow decent if a living player is on it +Don't allow to descend if a player is on it and is alive =============== */ void Touch_Plat( gentity_t *ent, gentity_t *other, trace_t *trace ) @@ -1860,7 +1917,8 @@ void SP_func_plat( gentity_t *ent ) G_SpawnString( "soundPos1", "sound/movers/plats/pt1_end.wav", &s ); ent->soundPos1 = G_SoundIndex( s ); - VectorClear( ent->s.angles ); + VectorClear( ent->s.apos.trBase ); + VectorClear( ent->r.currentAngles ); G_SpawnFloat( "speed", "200", &ent->speed ); G_SpawnInt( "dmg", "2", &ent->damage ); @@ -1876,7 +1934,7 @@ void SP_func_plat( gentity_t *ent ) height = ( ent->r.maxs[ 2 ] - ent->r.mins[ 2 ] ) - lip; // pos1 is the rest (bottom) position, pos2 is the top - VectorCopy( ent->s.origin, ent->pos2 ); + VectorCopy( ent->r.currentOrigin, ent->pos2 ); VectorCopy( ent->pos2, ent->pos1 ); ent->pos1[ 2 ] -= height; @@ -1921,7 +1979,7 @@ void Touch_Button( gentity_t *ent, gentity_t *other, trace_t *trace ) /*QUAKED func_button (0 .5 .8) ? -When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again. +When a button is touched, it moves some distance in the direction of its angle, triggers all of its targets, waits some time, then returns to its original position where it can be triggered again. "model2" .md3 model to also draw "angle" determines the opening direction @@ -1953,14 +2011,16 @@ void SP_func_button( gentity_t *ent ) ent->wait *= 1000; // first position - VectorCopy( ent->s.origin, ent->pos1 ); + VectorCopy( ent->r.currentOrigin, ent->pos1 ); + G_SetMovedir( ent->r.currentAngles, ent->movedir ); + VectorClear( ent->s.apos.trBase ); + VectorClear( ent->r.currentAngles ); // calculate second position trap_SetBrushModel( ent, ent->model ); G_SpawnFloat( "lip", "4", &lip ); - G_SetMovedir( ent->s.angles, ent->movedir ); abs_movedir[ 0 ] = fabs( ent->movedir[ 0 ] ); abs_movedir[ 1 ] = fabs( ent->movedir[ 1 ] ); abs_movedir[ 2 ] = fabs( ent->movedir[ 2 ] ); @@ -2031,8 +2091,8 @@ void Reached_Train( gentity_t *ent ) // set the new trajectory ent->nextTrain = next->nextTrain; - VectorCopy( next->s.origin, ent->pos1 ); - VectorCopy( next->nextTrain->s.origin, ent->pos2 ); + VectorCopy( next->r.currentOrigin, ent->pos1 ); + VectorCopy( next->nextTrain->r.currentOrigin, ent->pos2 ); // if the path_corner has a speed, use that if( next->speed ) @@ -2056,6 +2116,19 @@ void Reached_Train( gentity_t *ent ) ent->s.pos.trDuration = length * 1000 / speed; + // Be sure to send to clients after any fast move case + ent->r.svFlags &= ~SVF_NOCLIENT; + + // Fast move case + if( ent->s.pos.trDuration < 1 ) + { + // As trDuration is used later in a division, we need to avoid that case now + ent->s.pos.trDuration = 1; + + // Don't send entity to clients so it becomes really invisible + ent->r.svFlags |= SVF_NOCLIENT; + } + // looping sound ent->s.loopSound = next->soundLoop; @@ -2160,7 +2233,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) if( !path->target ) { G_Printf( "Train corner at %s without a target\n", - vtos( path->s.origin ) ); + vtos( path->r.currentOrigin ) ); return; } @@ -2175,7 +2248,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) if( !next ) { G_Printf( "Train corner at %s without a target path_corner\n", - vtos( path->s.origin ) ); + vtos( path->r.currentOrigin ) ); return; } } while( strcmp( next->classname, "path_corner" ) ); @@ -2199,7 +2272,7 @@ void SP_path_corner( gentity_t *self ) { if( !self->targetname ) { - G_Printf( "path_corner with no targetname at %s\n", vtos( self->s.origin ) ); + G_Printf( "path_corner with no targetname at %s\n", vtos( self->r.currentOrigin ) ); G_FreeEntity( self ); return; } @@ -2231,16 +2304,16 @@ void Blocked_Train( gentity_t *self, gentity_t *other ) vec3_t dir; gentity_t *tent; - if( other->biteam == BIT_ALIENS ) + if( other->buildableTeam == TEAM_ALIENS ) { VectorCopy( other->s.origin2, dir ); - tent = G_TempEntity( other->s.origin, EV_ALIEN_BUILDABLE_EXPLOSION ); + tent = G_TempEntity( other->r.currentOrigin, EV_ALIEN_BUILDABLE_EXPLOSION ); tent->s.eventParm = DirToByte( dir ); } - else if( other->biteam == BIT_HUMANS ) + else if( other->buildableTeam == TEAM_HUMANS ) { VectorSet( dir, 0.0f, 0.0f, 1.0f ); - tent = G_TempEntity( other->s.origin, EV_HUMAN_BUILDABLE_EXPLOSION ); + tent = G_TempEntity( other->r.currentOrigin, EV_HUMAN_BUILDABLE_EXPLOSION ); tent->s.eventParm = DirToByte( dir ); } } @@ -2271,7 +2344,8 @@ The train spawns at the first target it is pointing at. */ void SP_func_train( gentity_t *self ) { - VectorClear( self->s.angles ); + VectorClear( self->s.apos.trBase ); + VectorClear( self->r.currentAngles ); if( self->spawnflags & TRAIN_BLOCK_STOPS ) self->damage = 0; @@ -2318,10 +2392,12 @@ A bmodel that just sits there, doing nothing. Can be used for conditional walls */ void SP_func_static( gentity_t *ent ) { + vec3_t savedOrigin; trap_SetBrushModel( ent, ent->model ); + VectorCopy( ent->r.currentOrigin, savedOrigin ); InitMover( ent ); - VectorCopy( ent->s.origin, ent->s.pos.trBase ); - VectorCopy( ent->s.origin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->s.pos.trBase ); } @@ -2347,6 +2423,8 @@ check either the X_AXIS or Y_AXIS box to change that. */ void SP_func_rotating( gentity_t *ent ) { + vec3_t savedOrigin; + if( !ent->speed ) ent->speed = 100; @@ -2364,11 +2442,10 @@ void SP_func_rotating( gentity_t *ent ) ent->damage = 2; trap_SetBrushModel( ent, ent->model ); + VectorCopy( ent->r.currentOrigin, savedOrigin ); InitMover( ent ); - - VectorCopy( ent->s.origin, ent->s.pos.trBase ); - VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); - VectorCopy( ent->s.apos.trBase, ent->r.currentAngles ); + VectorCopy( savedOrigin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->s.pos.trBase ); trap_LinkEntity( ent ); } @@ -2397,6 +2474,7 @@ void SP_func_bobbing( gentity_t *ent ) { float height; float phase; + vec3_t savedOrigin; G_SpawnFloat( "speed", "4", &ent->speed ); G_SpawnFloat( "height", "32", &height ); @@ -2404,10 +2482,10 @@ void SP_func_bobbing( gentity_t *ent ) G_SpawnFloat( "phase", "0", &phase ); trap_SetBrushModel( ent, ent->model ); + VectorCopy( ent->r.currentOrigin, savedOrigin ); InitMover( ent ); - - VectorCopy( ent->s.origin, ent->s.pos.trBase ); - VectorCopy( ent->s.origin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->s.pos.trBase ); ent->s.pos.trDuration = ent->speed * 1000; ent->s.pos.trTime = ent->s.pos.trDuration * phase; @@ -2448,6 +2526,7 @@ void SP_func_pendulum( gentity_t *ent ) float length; float phase; float speed; + vec3_t savedOrigin; G_SpawnFloat( "speed", "30", &speed ); G_SpawnInt( "dmg", "2", &ent->damage ); @@ -2465,12 +2544,10 @@ void SP_func_pendulum( gentity_t *ent ) ent->s.pos.trDuration = ( 1000 / freq ); + VectorCopy( ent->r.currentOrigin, savedOrigin ); InitMover( ent ); - - VectorCopy( ent->s.origin, ent->s.pos.trBase ); - VectorCopy( ent->s.origin, ent->r.currentOrigin ); - - VectorCopy( ent->s.angles, ent->s.apos.trBase ); + VectorCopy( savedOrigin, ent->r.currentOrigin ); + VectorCopy( savedOrigin, ent->s.pos.trBase ); ent->s.apos.trDuration = 1000 / freq; ent->s.apos.trTime = ent->s.apos.trDuration * phase; |