diff options
-rw-r--r-- | src/game/g_combat.c | 3 | ||||
-rw-r--r-- | src/game/g_local.h | 8 | ||||
-rw-r--r-- | src/game/g_mover.c | 424 | ||||
-rw-r--r-- | src/game/g_spawn.c | 3 |
4 files changed, 401 insertions, 37 deletions
diff --git a/src/game/g_combat.c b/src/game/g_combat.c index e7088a00..3a04ad44 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -859,7 +859,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, // shootable doors / buttons don't actually have any health if( targ->s.eType == ET_MOVER ) { - if( targ->use && targ->moverState == MOVER_POS1 ) + if( targ->use && ( targ->moverState == MOVER_POS1 || + targ->moverState == ROTATOR_POS1 ) ) targ->use( targ, inflictor, attacker ); return; diff --git a/src/game/g_local.h b/src/game/g_local.h index 27ee0aa3..708a0c45 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -49,7 +49,12 @@ typedef enum MOVER_POS1, MOVER_POS2, MOVER_1TO2, - MOVER_2TO1 + MOVER_2TO1, + + ROTATOR_POS1, + ROTATOR_POS2, + ROTATOR_1TO2, + ROTATOR_2TO1 } moverState_t; #define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3" @@ -106,6 +111,7 @@ struct gentity_s gentity_t *nextTrain; gentity_t *prevTrain; vec3_t pos1, pos2; + float rotatorAngle; char *message; diff --git a/src/game/g_mover.c b/src/game/g_mover.c index ea6d6b54..8000bdc0 100644 --- a/src/game/g_mover.c +++ b/src/game/g_mover.c @@ -73,8 +73,8 @@ G_CreateRotationMatrix */ void G_CreateRotationMatrix( vec3_t angles, vec3_t matrix[ 3 ] ) { - AngleVectors( angles, matrix[ 0 ], matrix[ 1 ], matrix[ 2 ] ); - VectorInverse( matrix[ 1 ] ); + AngleVectors( angles, matrix[ 0 ], matrix[ 1 ], matrix[ 2 ] ); + VectorInverse( matrix[ 1 ] ); } /* @@ -84,15 +84,15 @@ G_TransposeMatrix */ void G_TransposeMatrix( vec3_t matrix[ 3 ], vec3_t transpose[ 3 ] ) { - int i, j; + int i, j; - for( i = 0; i < 3; i++ ) + for( i = 0; i < 3; i++ ) { - for( j = 0; j < 3; j++ ) + for( j = 0; j < 3; j++ ) { - transpose[ i ][ j ] = matrix[ j ][ i ]; - } - } + transpose[ i ][ j ] = matrix[ j ][ i ]; + } + } } /* @@ -102,12 +102,12 @@ G_RotatePoint */ void G_RotatePoint( vec3_t point, vec3_t matrix[ 3 ] ) { - vec3_t tvec; + vec3_t tvec; - VectorCopy( point, tvec ); - point[ 0 ] = DotProduct( matrix[ 0 ], tvec ); - point[ 1 ] = DotProduct( matrix[ 1 ], tvec ); - point[ 2 ] = DotProduct( matrix[ 2 ], tvec ); + VectorCopy( point, tvec ); + point[ 0 ] = DotProduct( matrix[ 0 ], tvec ); + point[ 1 ] = DotProduct( matrix[ 1 ], tvec ); + point[ 2 ] = DotProduct( matrix[ 2 ], tvec ); } /* @@ -144,30 +144,30 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v } pushed_p++; - // try moving the contacted entity - // figure movement due to the pusher's amove - G_CreateRotationMatrix( amove, transpose ); - G_TransposeMatrix( transpose, matrix ); + // try moving the contacted entity + // figure movement due to the pusher's amove + G_CreateRotationMatrix( amove, transpose ); + G_TransposeMatrix( transpose, matrix ); + + if( check->client ) + VectorSubtract( check->client->ps.origin, pusher->r.currentOrigin, org ); + else + VectorSubtract( check->s.pos.trBase, pusher->r.currentOrigin, org ); - if( check->client ) - VectorSubtract( check->client->ps.origin, pusher->r.currentOrigin, org ); - else - VectorSubtract( check->s.pos.trBase, pusher->r.currentOrigin, org ); + VectorCopy( org, org2 ); + G_RotatePoint( org2, matrix ); + VectorSubtract( org2, org, move2 ); + // add movement + VectorAdd( check->s.pos.trBase, move, check->s.pos.trBase ); + VectorAdd( check->s.pos.trBase, move2, check->s.pos.trBase ); - VectorCopy( org, org2 ); - G_RotatePoint( org2, matrix ); - VectorSubtract( org2, org, move2 ); - // add movement - VectorAdd( check->s.pos.trBase, move, check->s.pos.trBase ); - VectorAdd( check->s.pos.trBase, move2, check->s.pos.trBase ); - if( check->client ) { - VectorAdd( check->client->ps.origin, move, check->client->ps.origin ); - VectorAdd( check->client->ps.origin, move2, check->client->ps.origin ); - // make sure the client's view rotates when on a rotating mover - check->client->ps.delta_angles[ YAW ] += ANGLE2SHORT( amove[ YAW ] ); - } + VectorAdd( check->client->ps.origin, move, check->client->ps.origin ); + VectorAdd( check->client->ps.origin, move2, check->client->ps.origin ); + // make sure the client's view rotates when on a rotating mover + check->client->ps.delta_angles[ YAW ] += ANGLE2SHORT( amove[ YAW ] ); + } // may have pushed them off an edge if( check->s.groundEntityNum != pusher->s.number ) @@ -407,6 +407,13 @@ void G_MoverTeam( gentity_t *ent ) part->reached( part ); } } + if ( part->s.apos.trType == TR_LINEAR_STOP ) { + if ( level.time >= part->s.apos.trTime + part->s.apos.trDuration ) { + if ( part->reached ) { + part->reached( part ); + } + } + } } } @@ -454,6 +461,8 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) ent->moverState = moverState; ent->s.pos.trTime = time; + ent->s.apos.trTime = time; + switch( moverState ) { case MOVER_POS1: @@ -481,9 +490,36 @@ void SetMoverState( gentity_t *ent, moverState_t moverState, int time ) VectorScale( delta, f, ent->s.pos.trDelta ); ent->s.pos.trType = TR_LINEAR_STOP; break; + + case ROTATOR_POS1: + VectorCopy( ent->pos1, ent->s.apos.trBase ); + ent->s.apos.trType = TR_STATIONARY; + break; + + case ROTATOR_POS2: + VectorCopy( ent->pos2, ent->s.apos.trBase ); + ent->s.apos.trType = TR_STATIONARY; + break; + + case ROTATOR_1TO2: + VectorCopy( ent->pos1, ent->s.apos.trBase ); + VectorSubtract( ent->pos2, ent->pos1, delta ); + f = 1000.0 / ent->s.apos.trDuration; + VectorScale( delta, f, ent->s.apos.trDelta ); + ent->s.apos.trType = TR_LINEAR_STOP; + break; + + case ROTATOR_2TO1: + VectorCopy( ent->pos2, ent->s.apos.trBase ); + VectorSubtract( ent->pos1, ent->pos2, delta ); + f = 1000.0 / ent->s.apos.trDuration; + VectorScale( delta, f, ent->s.apos.trDelta ); + ent->s.apos.trType = TR_LINEAR_STOP; + break; } BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin ); + BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles ); trap_LinkEntity( ent ); } @@ -525,6 +561,24 @@ void ReturnToPos1( gentity_t *ent ) /* ================ +ReturnToApos1 +================ +*/ +void ReturnToApos1( gentity_t *ent ) +{ + MatchTeam( ent, ROTATOR_2TO1, level.time ); + + // looping sound + ent->s.loopSound = ent->soundLoop; + + // starting sound + if( ent->sound2to1 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); +} + + +/* +================ Reached_BinaryMover ================ */ @@ -565,6 +619,38 @@ void Reached_BinaryMover( gentity_t *ent ) if( ent->teammaster == ent || !ent->teammaster ) trap_AdjustAreaPortalState( ent, qfalse ); } + else if( ent->moverState == ROTATOR_1TO2 ) + { + // reached pos2 + SetMoverState( ent, ROTATOR_POS2, level.time ); + + // play sound + if( ent->soundPos2 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos2 ); + + // return to apos1 after a delay + ent->think = ReturnToApos1; + ent->nextthink = level.time + ent->wait; + + // fire targets + if( !ent->activator ) + ent->activator = ent; + + G_UseTargets( ent, ent->activator ); + } + else if( ent->moverState == ROTATOR_2TO1 ) + { + // reached pos1 + SetMoverState( ent, ROTATOR_POS1, level.time ); + + // play sound + if( ent->soundPos1 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->soundPos1 ); + + // close areaportals + if( ent->teammaster == ent || !ent->teammaster ) + trap_AdjustAreaPortalState( ent, qfalse ); + } else G_Error( "Reached_BinaryMover: bad moverState" ); } @@ -649,6 +735,67 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) return; } + + if( ent->moverState == ROTATOR_POS1 ) + { + // 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 ); + + // starting sound + if( ent->sound1to2 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 ); + + // looping sound + ent->s.loopSound = ent->soundLoop; + + // open areaportal + if( ent->teammaster == ent || !ent->teammaster ) + trap_AdjustAreaPortalState( ent, qtrue ); + + return; + } + + // if all the way up, just delay before coming down + if( ent->moverState == ROTATOR_POS2 ) + { + ent->nextthink = level.time + ent->wait; + return; + } + + // only partway down before reversing + if( ent->moverState == ROTATOR_2TO1 ) + { + total = ent->s.apos.trDuration; + partial = level.time - ent->s.time; + + if( partial > total ) + partial = total; + + MatchTeam( ent, ROTATOR_1TO2, level.time - ( total - partial ) ); + + if( ent->sound1to2 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound1to2 ); + + return; + } + + // only partway up before reversing + if( ent->moverState == ROTATOR_1TO2 ) + { + total = ent->s.apos.trDuration; + partial = level.time - ent->s.time; + + if( partial > total ) + partial = total; + + MatchTeam( ent, ROTATOR_2TO1, level.time - ( total - partial ) ); + + if( ent->sound2to1 ) + G_AddEvent( ent, EV_GENERAL_SOUND, ent->sound2to1 ); + + return; + } } @@ -734,6 +881,91 @@ void InitMover( gentity_t *ent ) /* +================ +InitRotator + +"pos1", "pos2", and "speed" should be set before calling, +so the movement delta can be calculated +================ +*/ +void InitRotator( gentity_t *ent ) +{ + vec3_t move; + float angle; + float light; + vec3_t color; + qboolean lightSet, colorSet; + char *sound; + + // 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 "color" or "light" keys are set, setup constantLight + lightSet = G_SpawnFloat( "light", "100", &light ); + colorSet = G_SpawnVector( "color", "1 1 1", color ); + + if( lightSet || colorSet ) + { + int r, g, b, i; + + r = color[ 0 ] * 255; + + if( r > 255 ) + r = 255; + + g = color[ 1 ] * 255; + + if( g > 255 ) + g = 255; + + b = color[ 2 ] * 255; + + if( b > 255 ) + b = 255; + + i = light / 4; + + if( i > 255 ) + i = 255; + + ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 ); + } + + + ent->use = Use_BinaryMover; + ent->reached = Reached_BinaryMover; + + 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 ); + + ent->s.apos.trType = TR_STATIONARY; + VectorCopy( ent->pos1, ent->s.apos.trBase ); + + // calculate time to reach second position from speed + VectorSubtract( ent->pos2, ent->pos1, move ); + angle = VectorLength( move ); + + if( ! ent->speed ) + ent->speed = 120; + + VectorScale( move, ent->speed, ent->s.apos.trDelta ); + ent->s.apos.trDuration = angle * 1000 / ent->speed; + + if( ent->s.apos.trDuration <= 0 ) + ent->s.apos.trDuration = 1; +} + + +/* =============================================================================== DOOR @@ -924,10 +1156,13 @@ void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) { // if the door is not open and not opening if( ent->parent->moverState != MOVER_1TO2 && - ent->parent->moverState != MOVER_POS2 ) + ent->parent->moverState != MOVER_POS2 && + ent->parent->moverState != ROTATOR_1TO2 && + ent->parent->moverState != ROTATOR_POS2 ) Touch_DoorTriggerSpectator( ent, other, trace ); } - else if( ent->parent->moverState != MOVER_1TO2 ) + else if( ent->parent->moverState != MOVER_1TO2 && + ent->parent->moverState != ROTATOR_1TO2 ) Use_BinaryMover( ent->parent, ent, other ); } @@ -1090,6 +1325,125 @@ void SP_func_door( gentity_t *ent ) } } +/*QUAKED func_door_rotating (0 .5 .8) START_OPEN CRUSHER REVERSE TOGGLE X_AXIS Y_AXIS + * This is the rotating door... just as the name suggests it's a door that rotates + * START_OPEN the door to moves to its destination when spawned, and operate in reverse. + * REVERSE if you want the door to open in the other direction, use this switch. + * TOGGLE wait in both the start and end states for a trigger event. + * X_AXIS open on the X-axis instead of the Z-axis + * Y_AXIS open on the Y-axis instead of the Z-axis + * + * You need to have an origin brush as part of this entity. The center of that brush will be + * the point around which it is rotated. It will rotate around the Z axis by default. You can + * check either the X_AXIS or Y_AXIS box to change that. + * + * "model2" .md3 model to also draw + * "distance" how many degrees the door will open + * "speed" how fast the door will open (degrees/second) + * "color" constantLight color + * "light" constantLight radius + * */ + +void SP_func_door_rotating( gentity_t *ent ) +{ + char *s; + + G_SpawnString( "sound2to1", "sound/movers/doors/dr1_strt.wav", &s ); + ent->sound2to1 = G_SoundIndex( s ); + G_SpawnString( "sound1to2", "sound/movers/doors/dr1_strt.wav", &s ); + ent->sound1to2 = G_SoundIndex( s ); + + G_SpawnString( "soundPos2", "sound/movers/doors/dr1_end.wav", &s ); + ent->soundPos2 = G_SoundIndex( s ); + G_SpawnString( "soundPos1", "sound/movers/doors/dr1_end.wav", &s ); + ent->soundPos1 = G_SoundIndex( s ); + + ent->blocked = Blocked_Door; + + //default speed of 120 + if( !ent->speed ) + ent->speed = 120; + + // if speed is negative, positize it and add reverse flag + if( ent->speed < 0 ) + { + ent->speed *= -1; + ent->spawnflags |= 8; + } + + // default of 2 seconds + if( !ent->wait ) + ent->wait = 2; + + ent->wait *= 1000; + + // set the axis of rotation + VectorClear( ent->movedir ); + VectorClear( ent->s.angles ); + + if( ent->spawnflags & 32 ) + ent->movedir[ 2 ] = 1.0; + else if( ent->spawnflags & 64 ) + ent->movedir[ 0 ] = 1.0; + else + ent->movedir[ 1 ] = 1.0; + + // reverse direction if necessary + if( ent->spawnflags & 8 ) + VectorNegate ( ent->movedir, ent->movedir ); + + // default distance of 90 degrees. This is something the mapper should not + // leave out, so we'll tell him if he does. + if( !ent->rotatorAngle ) + { + G_Printf( "%s at %s with no rotatorAngle set.\n", + ent->classname, vtos( ent->s.origin ) ); + + ent->rotatorAngle = 90.0; + } + + VectorCopy( ent->s.angles, ent->pos1 ); + trap_SetBrushModel( ent, ent->model ); + VectorMA( ent->pos1, ent->rotatorAngle, ent->movedir, ent->pos2 ); + + // if "start_open", reverse position 1 and 2 + if( ent->spawnflags & 1 ) + { + vec3_t temp; + + VectorCopy( ent->pos2, temp ); + VectorCopy( ent->s.angles, 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; + + if( ent->targetname || health ) + { + // non touch/shoot doors + ent->think = Think_MatchTeam; + } + else + ent->think = Think_SpawnNewDoorTrigger; + } +} + /* =============================================================================== diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 36ae42c8..71197932 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -133,6 +133,7 @@ field_t fields[ ] = {"radius", FOFS(pos2), F_VECTOR}, {"acceleration", FOFS(acceleration), F_VECTOR}, {"animation", FOFS(animation), F_VECTOR4}, + {"rotatorAngle", FOFS(rotatorAngle), F_FLOAT}, //TA {"targetShaderName", FOFS(targetShaderName), F_LSTRING}, {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING}, @@ -167,6 +168,7 @@ void SP_func_bobbing( gentity_t *ent ); void SP_func_pendulum( gentity_t *ent ); void SP_func_button( gentity_t *ent ); void SP_func_door( gentity_t *ent ); +void SP_func_door_rotating( gentity_t *ent ); //TA void SP_func_train( gentity_t *ent ); void SP_func_timer( gentity_t *self); @@ -230,6 +232,7 @@ spawn_t spawns[ ] = {"func_plat", SP_func_plat}, {"func_button", SP_func_button}, {"func_door", SP_func_door}, + {"func_door_rotating", SP_func_door_rotating}, //TA {"func_static", SP_func_static}, {"func_rotating", SP_func_rotating}, {"func_bobbing", SP_func_bobbing}, |