summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/g_active.c15
-rw-r--r--src/game/g_buildable.c40
-rw-r--r--src/game/g_client.c11
-rw-r--r--src/game/g_cmds.c43
-rw-r--r--src/game/g_combat.c2
-rw-r--r--src/game/g_local.h23
-rw-r--r--src/game/g_main.c196
-rw-r--r--src/game/tremulous.h10
8 files changed, 286 insertions, 54 deletions
diff --git a/src/game/g_active.c b/src/game/g_active.c
index f9e14243..cad4a2cf 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -349,12 +349,15 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) )
{
- if( client->pers.teamSelection == PTE_NONE )
- G_TriggerMenu( client->ps.clientNum, MN_TEAM );
- else if( client->pers.teamSelection == PTE_ALIENS )
- G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
- else if( client->pers.teamSelection == PTE_HUMANS )
- G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
+ if( client->pers.classSelection == PCL_NONE )
+ {
+ if( client->pers.teamSelection == PTE_NONE )
+ G_TriggerMenu( client->ps.clientNum, MN_TEAM );
+ else if( client->pers.teamSelection == PTE_ALIENS )
+ G_TriggerMenu( client->ps.clientNum, MN_A_CLASS );
+ else if( client->pers.teamSelection == PTE_HUMANS )
+ G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN );
+ }
}
}
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index fec593f2..5d487e4e 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -1968,6 +1968,33 @@ void HTeslaGen_Think( gentity_t *self )
/*
================
+HSpawn_Disappear
+
+Called when a human spawn is destroyed before it is spawned
+think function
+================
+*/
+void HSpawn_Disappear( gentity_t *self )
+{
+ vec3_t dir;
+
+ // we don't have a valid direction, so just point straight up
+ dir[ 0 ] = dir[ 1 ] = 0;
+ dir[ 2 ] = 1;
+
+ self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed
+ self->timestamp = level.time;
+
+ self->think = freeBuildable;
+ self->nextthink = level.time + 100;
+
+ self->r.contents = 0; //stop collisions...
+ trap_LinkEntity( self ); //...requires a relink
+}
+
+
+/*
+================
HSpawn_blast
Called when a human spawn explodes
@@ -2012,14 +2039,19 @@ void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
G_setIdleBuildableAnim( self, BANIM_DESTROYED );
self->die = nullDieFunction;
- self->think = HSpawn_Blast;
self->powered = qfalse; //free up power
self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
if( self->spawned )
+ {
+ self->think = HSpawn_Blast;
self->nextthink = level.time + HUMAN_DETONATION_DELAY;
+ }
else
+ {
+ self->think = HSpawn_Disappear;
self->nextthink = level.time; //blast immediately
+ }
if( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
{
@@ -2124,6 +2156,12 @@ void G_BuildableThink( gentity_t *ent, int msec )
ent->health = bHealth;
}
+ if( ent->clientSpawnTime > 0 )
+ ent->clientSpawnTime -= msec;
+
+ if( ent->clientSpawnTime < 0 )
+ ent->clientSpawnTime = 0;
+
//fall back on normal physics routines
G_Physics( ent, msec );
}
diff --git a/src/game/g_client.c b/src/game/g_client.c
index dc1d37bf..4645780c 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -294,6 +294,9 @@ gentity_t *SelectAlienSpawnPoint( void )
if( !spot->s.groundEntityNum )
continue;
+
+ if( spot->clientSpawnTime > 0 )
+ continue;
if( G_CheckSpawnPoint( spot->s.origin, spot->s.origin2, BA_A_SPAWN, NULL ) != NULL )
continue;
@@ -342,6 +345,9 @@ gentity_t *SelectHumanSpawnPoint( void )
if( !spot->s.groundEntityNum )
continue;
+ if( spot->clientSpawnTime > 0 )
+ continue;
+
if( G_CheckSpawnPoint( spot->s.origin, spot->s.origin2, BA_H_SPAWN, NULL ) != NULL )
continue;
@@ -1250,6 +1256,11 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
{
//start spawn animation on spawnPoint
G_setBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue );
+
+ if( spawnPoint->biteam == PTE_ALIENS )
+ spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME;
+ else if( spawnPoint->biteam == PTE_HUMANS )
+ spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME;
}
}
client->pers.teamState.state = TEAM_ACTIVE;
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 00ba30d2..bdc0a994 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -311,6 +311,9 @@ Cmd_Kill_f
*/
void Cmd_Kill_f( gentity_t *ent )
{
+ if( ent->client->sess.sessionTeam == TEAM_SPECTATOR )
+ return;
+
if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE )
return;
@@ -364,7 +367,7 @@ void Cmd_Team_f( gentity_t *ent )
{
level.bankCredits[ ent->client->ps.clientNum ] = 0;
ent->client->ps.persistant[ PERS_CREDIT ] = 0;
- ent->client->pers.classSelection = 0;
+ ent->client->pers.classSelection = PCL_NONE;
ClientSpawn( ent, NULL, NULL, NULL );
}
@@ -1039,7 +1042,8 @@ void Cmd_Class_f( gentity_t *ent )
else
{
//spawning from an egg
- ent->client->pers.classSelection = BG_FindClassNumForName( s );
+ ent->client->pers.classSelection =
+ ent->client->ps.stats[ STAT_PCLASS ] = BG_FindClassNumForName( s );
if( ent->client->pers.classSelection != PCL_NONE )
{
@@ -1048,20 +1052,8 @@ void Cmd_Class_f( gentity_t *ent )
if( allowedClasses[ i ] == ent->client->pers.classSelection &&
BG_FindStagesForClass( ent->client->pers.classSelection, g_alienStage.integer ) )
{
- if( ( spawn = SelectTremulousSpawnPoint( ent->client->pers.teamSelection,
- spawn_origin, spawn_angles ) ) &&
- level.numAlienSpawns > 0 ) //sanity check
- {
- ent->client->sess.sessionTeam = TEAM_FREE;
- ClientUserinfoChanged( clientNum );
- ClientSpawn( ent, spawn, spawn_origin, spawn_angles );
- return;
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"No suitable spawns available\n\"" ) );
- return;
- }
+ G_PushSpawnQueue( &level.alienSpawnQueue, clientNum );
+ return;
}
}
@@ -1084,7 +1076,8 @@ void Cmd_Class_f( gentity_t *ent )
return;
}
- ent->client->pers.classSelection = PCL_H_BASE;
+ ent->client->pers.classSelection =
+ ent->client->ps.stats[ STAT_PCLASS ] = PCL_H_BASE;
//set the item to spawn with
if( !Q_stricmp( s, BG_FindNameForWeapon( WP_MACHINEGUN ) ) )
@@ -1098,19 +1091,7 @@ void Cmd_Class_f( gentity_t *ent )
return;
}
- if( ( spawn = SelectTremulousSpawnPoint( ent->client->pers.teamSelection,
- spawn_origin, spawn_angles ) ) &&
- level.numHumanSpawns > 0 ) //sanity check
- {
- ent->client->sess.sessionTeam = TEAM_FREE;
- ClientUserinfoChanged( clientNum );
- ClientSpawn( ent, spawn, spawn_origin, spawn_angles );
- }
- else
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"No suitable spawns available\n\"" ) );
- return;
- }
+ G_PushSpawnQueue( &level.humanSpawnQueue, clientNum );
}
else if( ent->client->pers.teamSelection == PTE_NONE )
{
@@ -1145,7 +1126,7 @@ void Cmd_Destroy_f( gentity_t *ent, qboolean deconstruct )
trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
traceEnt = &g_entities[ tr.entityNum ];
- if( tr.fraction < 1.0 &&
+ if( tr.fraction < 1.0f &&
( traceEnt->s.eType == ET_BUILDABLE ) &&
( traceEnt->biteam == ent->client->pers.teamSelection ) &&
( ( ent->client->ps.weapon >= WP_ABUILD ) &&
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index d5e6f2f7..675b917d 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -297,7 +297,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
Cmd_Score_f( g_entities + i );
}
- self->client->pers.classSelection = 0; //TA: reset the classtype
+ self->client->pers.classSelection = PCL_NONE; //TA: reset the classtype
self->takedamage = qtrue; // can still be gibbed
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 2026470d..ff8b7595 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -199,6 +199,7 @@ struct gentity_s
int overmindSpawnsTimer;
int nextPhysicsTime; //TA: buildables don't need to check what they're sitting on
// every single frame.. so only do it periodically
+ int clientSpawnTime; //TA: the time until this spawn can spawn a client
int credits[ MAX_CLIENTS ]; //TA: human credits for each client
qboolean creditsHash[ MAX_CLIENTS ]; //TA: track who has claimed credit
@@ -389,6 +390,25 @@ struct gclient_s
int retriggerArmouryMenu; //TA: frame number to retrigger the armoury menu
};
+
+typedef struct spawnQueue_s
+{
+ int clients[ MAX_CLIENTS ];
+
+ int front, back;
+} spawnQueue_t;
+
+#define QUEUE_PLUS1(x) (((x)+1)%MAX_CLIENTS)
+#define QUEUE_MINUS1(x) (((x)-1)%MAX_CLIENTS)
+
+int G_InitSpawnQueue( spawnQueue_t *sq );
+int G_GetSpawnQueueLength( spawnQueue_t *sq );
+int G_PopSpawnQueue( spawnQueue_t *sq );
+void G_PushSpawnQueue( spawnQueue_t *sq, int clientNum );
+qboolean G_RemoveFromSpawnQueue( spawnQueue_t *sq, int clientNum );
+int G_GetPosInSpawnQueue( spawnQueue_t *sq, int clientNum );
+
+
#define MAX_LOCDAMAGE_TEXT 8192
#define MAX_LOCDAMAGE_REGIONS 16
@@ -524,6 +544,9 @@ typedef struct
qboolean overmindPresent;
pTeam_t lastWin;
+
+ spawnQueue_t alienSpawnQueue;
+ spawnQueue_t humanSpawnQueue;
} level_locals_t;
//
diff --git a/src/game/g_main.c b/src/game/g_main.c
index f57b385f..53b61108 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -186,8 +186,8 @@ void G_RunFrame( int levelTime );
void G_ShutdownGame( int restart );
void CheckExitRules( void );
-void countSpawns( void );
-void calculateBuildPoints( void );
+void G_CountSpawns( void );
+void G_CalculateBuildPoints( void );
/*
================
@@ -527,6 +527,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
G_InitDamageLocations( );
G_GenerateParticleFileList( );
G_InitMapRotations( );
+ G_InitSpawnQueue( &level.alienSpawnQueue );
+ G_InitSpawnQueue( &level.humanSpawnQueue );
if( g_debugMapRotation.integer )
G_PrintRotations( );
@@ -542,7 +544,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
G_RemapTeamShaders( );
//TA: so the server counts the spawns without a client attached
- countSpawns( );
+ G_CountSpawns( );
}
@@ -667,12 +669,180 @@ int QDECL SortRanks( const void *a, const void *b )
/*
============
-countSpawns
+G_InitSpawnQueue
+
+Initialise a spawn queue
+============
+*/
+int G_InitSpawnQueue( spawnQueue_t *sq )
+{
+ sq->back = sq->front = 0;
+ sq->back = QUEUE_MINUS1( sq->back );
+}
+
+/*
+============
+G_GetSpawnQueueLength
+
+Return tha length of a spawn queue
+============
+*/
+int G_GetSpawnQueueLength( spawnQueue_t *sq )
+{
+/* if( sq->back < sq->front )
+ return ( sq->back + MAX_CLIENTS - sq->front + 1 ) % MAX_CLIENTS;
+ else*/
+ return ( sq->back - sq->front + 1 ) % MAX_CLIENTS;
+}
+
+/*
+============
+G_PopSpawnQueue
+
+Remove from front element from a spawn queue
+============
+*/
+int G_PopSpawnQueue( spawnQueue_t *sq )
+{
+ int popee = sq->front;
+
+ if( G_GetSpawnQueueLength( sq ) > 0 )
+ {
+ sq->front = QUEUE_PLUS1( sq->front );
+ return sq->clients[ popee ];
+ }
+ else
+ return -1;
+}
+
+/*
+============
+G_PushSpawnQueue
+
+Add an element to the back of the spawn queue
+============
+*/
+void G_PushSpawnQueue( spawnQueue_t *sq, int clientNum )
+{
+ sq->back = QUEUE_PLUS1( sq->back );
+ sq->clients[ sq->back ] = clientNum;
+}
+
+/*
+============
+G_RemoveFromSpawnQueue
+
+remove a specific client from a spawn queue
+============
+*/
+qboolean G_RemoveFromSpawnQueue( spawnQueue_t *sq, int clientNum )
+{
+ int i = sq->front;
+
+ do
+ {
+ if( sq->clients[ i ] == clientNum )
+ {
+ //and this kids, is why it would have
+ //been better to use an LL for internal
+ //representation
+ do
+ {
+ sq->clients[ i ] = sq->clients[ QUEUE_PLUS1( i ) ];
+
+ i = QUEUE_PLUS1( 1 );
+ } while( i != sq->back );
+
+ sq->back = QUEUE_MINUS1( sq->back );
+
+ return qtrue;
+ }
+
+ i = QUEUE_PLUS1( 1 );
+ } while( i != QUEUE_PLUS1( sq->back ) );
+
+ return qfalse;
+}
+
+/*
+============
+G_GetPosInSpawnQueue
+
+Get the position of a client in a spawn queue
+============
+*/
+int G_GetPosInSpawnQueue( spawnQueue_t *sq, int clientNum )
+{
+ int i = sq->front;
+
+ do
+ {
+ if( sq->clients[ i ] == clientNum )
+ {
+ if( i < sq->front )
+ return i + MAX_CLIENTS - sq->front + 1;
+ else
+ return i - sq->front + 1;
+ }
+
+ i = QUEUE_PLUS1( 1 );
+ } while( i != QUEUE_PLUS1( sq->back ) );
+
+ return -1;
+}
+
+/*
+============
+G_SpawnClients
+
+Spawn queued clients
+============
+*/
+void G_SpawnClients( pTeam_t team )
+{
+ int clientNum;
+ gentity_t *ent, *spawn;
+ vec3_t spawn_origin, spawn_angles;
+ spawnQueue_t *sq;
+ int numSpawns;
+
+ if( team == PTE_ALIENS )
+ {
+ sq = &level.alienSpawnQueue;
+ numSpawns = level.numAlienSpawns;
+ }
+ else if( team == PTE_HUMANS )
+ {
+ sq = &level.humanSpawnQueue;
+ numSpawns = level.numHumanSpawns;
+ }
+
+ if( G_GetSpawnQueueLength( sq ) > 0 && numSpawns > 0 )
+ {
+ if( ( spawn = SelectTremulousSpawnPoint( team, spawn_origin, spawn_angles ) ) )
+ {
+ clientNum = G_PopSpawnQueue( sq );
+
+ if( clientNum < 0 )
+ return;
+
+ ent = &g_entities[ clientNum ];
+
+ ent->client->sess.sessionTeam = TEAM_FREE;
+ ClientUserinfoChanged( clientNum );
+ ClientSpawn( ent, spawn, spawn_origin, spawn_angles );
+ }
+ }
+}
+
+/*
+============
+G_CountSpawns
Counts the number of spawns for each team
============
*/
-void countSpawns( void )
+void G_CountSpawns( void )
{
int i;
gentity_t *ent;
@@ -696,12 +866,12 @@ void countSpawns( void )
/*
============
-calculateBuildPoints
+G_CalculateBuildPoints
Recalculate the quantity of building points available to the teams
============
*/
-void calculateBuildPoints( void )
+void G_CalculateBuildPoints( void )
{
int i;
int bclass;
@@ -777,10 +947,10 @@ void calculateBuildPoints( void )
/*
============
-CalculateStages
+G_CalculateStages
============
*/
-void CalculateStages( void )
+void G_CalculateStages( void )
{
float alienPlayerCountMod = (float)level.numAlienClients / PLAYER_COUNT_MOD;
float humanPlayerCountMod = (float)level.numAlienClients / PLAYER_COUNT_MOD;
@@ -1665,9 +1835,11 @@ void G_RunFrame( int levelTime )
end = trap_Milliseconds();
//TA:
- countSpawns( );
- calculateBuildPoints( );
- CalculateStages( );
+ G_CountSpawns( );
+ G_CalculateBuildPoints( );
+ G_CalculateStages( );
+ G_SpawnClients( PTE_ALIENS );
+ G_SpawnClients( PTE_HUMANS );
// see if it is time to end the level
CheckExitRules( );
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index 1c001c7a..707a0929 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -207,9 +207,9 @@
#define ASPAWN_CREEPSIZE 120
#define ASPAWN_VALUE 150
-#define BARRICADE_BP 8
+#define BARRICADE_BP 10
#define BARRICADE_BT 20000
-#define BARRICADE_HEALTH ABHM(350)
+#define BARRICADE_HEALTH ABHM(400)
#define BARRICADE_REGEN 12
#define BARRICADE_SPLASHDAMAGE 50
#define BARRICADE_SPLASHRADIUS 50
@@ -224,7 +224,7 @@
#define BOOSTER_CREEPSIZE 120
#define BOOSTER_INTERVAL 30000 //time in msec between uses (per player)
-#define ACIDTUBE_BP 5
+#define ACIDTUBE_BP 8
#define ACIDTUBE_BT 15000
#define ACIDTUBE_HEALTH ABHM(200)
#define ACIDTUBE_REGEN 8
@@ -293,6 +293,8 @@
#define ALIEN_POISON_DMG 30
#define ALIEN_POISON_DIVIDER (1.0f/1.32f) //about 1.0/(time`th root of damage)
+#define ALIEN_SPAWN_REPEAT_TIME 10000
+
/*
* HUMAN weapons
@@ -527,6 +529,8 @@
#define STAMINA_SPRINT_TAKE 8
#define STAMINA_LARMOUR_TAKE 4
+#define HUMAN_SPAWN_REPEAT_TIME 10000
+
/*
* Misc
*/