summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2003-08-19 03:03:41 +0000
committerTim Angus <tim@ngus.net>2003-08-19 03:03:41 +0000
commit653d19589c6c466292f396a9d298bc73fe0ea453 (patch)
tree57ef820fd8d3d1ed52d995c8e48130a0986d0fa7 /src
parent9d775be1fcf70285d3d55fa1f1541e088b2280a6 (diff)
* Buildables now take time to "warp in"
* A few cleanups here and there * Bye bye cg_creep.c
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_buildable.c40
-rw-r--r--src/cgame/cg_event.c9
-rw-r--r--src/cgame/cg_local.h1
-rw-r--r--src/cgame/cg_main.c1
-rw-r--r--src/game/bg_misc.c37
-rw-r--r--src/game/bg_public.h6
-rw-r--r--src/game/g_active.c8
-rw-r--r--src/game/g_buildable.c415
-rw-r--r--src/game/g_client.c56
-rw-r--r--src/game/g_cmds.c67
-rw-r--r--src/game/g_local.h5
-rw-r--r--src/game/g_main.c2
-rw-r--r--src/game/g_physics.c15
-rw-r--r--src/game/g_weapon.c4
14 files changed, 396 insertions, 270 deletions
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index a75169da..d1732f38 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -597,8 +597,8 @@ static void CG_BuildableParticleEffects( centity_t *cent )
{
entityState_t *es = &cent->currentState;
buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
- int health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT );
- float healthFrac = (float)health / 63.0f;
+ int health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
+ float healthFrac = (float)health / B_HEALTH_SCALE;
int smokeTime, sparkTime, i, bleedBlobs;
vec3_t origin;
vec3_t acc = { 0.0f, 0.0f, 50.0f };
@@ -704,8 +704,8 @@ static void CG_BuildableHealthBar( centity_t *cent )
es = &cent->currentState;
- health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT );
- progress = (float)health / 63.0f;
+ health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
+ progress = (float)health / B_HEALTH_SCALE;
if( progress < 0.0f )
progress = 0.0f;
@@ -773,19 +773,14 @@ CG_Buildable
void CG_Buildable( centity_t *cent )
{
refEntity_t ent;
- entityState_t *es;
+ entityState_t *es = &cent->currentState;
vec3_t angles;
vec3_t forward, surfNormal, xNormal, end, start, mins, maxs;
vec3_t refNormal = { 0.0f, 0.0f, 1.0f };
float rotAngle;
trace_t tr;
-
- es = &cent->currentState;
+ buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
- //add creep
- if( es->modelindex2 == BIT_ALIENS )
- CG_Creep( cent );
-
// if set to invisible, skip
if ( !es->modelindex || ( es->eFlags & EF_NODRAW ) )
return;
@@ -835,11 +830,24 @@ void CG_Buildable( centity_t *cent )
ent.nonNormalizedAxes = qfalse;
- //run animations
- CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
+ //add creep
+ if( team == BIT_ALIENS )
+ {
+ CG_Creep( cent );
+ //run animations
+ CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
+ }
+ else if( team == BIT_HUMANS )
+ {
+ if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ ent.customShader = cgs.media.humanSpawningShader;
+ else
+ CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
+ }
+
// add to refresh list
- trap_R_AddRefEntityToScene(&ent);
+ trap_R_AddRefEntityToScene( &ent );
//turret barrel bit
if( cg_buildables[ es->modelindex ].models[ 1 ] )
@@ -863,6 +871,8 @@ void CG_Buildable( centity_t *cent )
turretBarrel.frame = ent.frame;
turretBarrel.backlerp = ent.backlerp;
+ turretBarrel.customShader = ent.customShader;
+
trap_R_AddRefEntityToScene( &turretBarrel );
}
@@ -892,6 +902,8 @@ void CG_Buildable( centity_t *cent )
turretTop.frame = ent.frame;
turretTop.backlerp = ent.backlerp;
+ turretTop.customShader = ent.customShader;
+
trap_R_AddRefEntityToScene( &turretTop );
}
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 93dcca1d..cdfd8718 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -780,9 +780,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
case EV_BUILD_DELAY:
DEBUGNAME( "EV_BUILD_DELAY" );
- //FIXME: change to "negative" sound
- trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
- cg.lastBuildAttempt = cg.time;
+ if( clientNum == cg.predictedPlayerState.clientNum )
+ {
+ //FIXME: change to "negative" sound
+ trap_S_StartLocalSound( cgs.media.hitSound, CHAN_LOCAL_SOUND );
+ cg.lastBuildAttempt = cg.time;
+ }
break;
case EV_POISONCLOUD:
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index c5fbfbeb..b5e7238c 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -854,6 +854,7 @@ typedef struct
qhandle_t greenBuildShader;
qhandle_t redBuildShader;
qhandle_t noPowerShader;
+ qhandle_t humanSpawningShader;
// weapon effect models
qhandle_t bulletFlashModel;
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index f68c7da1..d52c77ec 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -727,6 +727,7 @@ static void CG_RegisterGraphics( void )
cgs.media.greenBuildShader = trap_R_RegisterShader("gfx/2d/greenbuild" );
cgs.media.redBuildShader = trap_R_RegisterShader("gfx/2d/redbuild" );
cgs.media.noPowerShader = trap_R_RegisterShader("gfx/2d/nopower" );
+ cgs.media.humanSpawningShader = trap_R_RegisterShader("models/buildables/replicator/rep_cyl" );
cgs.media.machinegunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/m_shell.md3" );
cgs.media.shotgunBrassModel = trap_R_RegisterModel( "models/weapons2/shells/s_shell.md3" );
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 1c07da59..88baff57 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -41,6 +41,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -73,6 +74,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -105,6 +107,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -137,6 +140,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
500, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -169,6 +173,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
TRAPPER_RANGE, //int turretRange;
TRAPPER_REPEAT, //int turretFireSpeed;
@@ -201,6 +206,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
OVERMIND_ATTACK_REPEAT,//int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -233,6 +239,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
150, //int nextthink;
+ 10000, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -265,6 +272,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -297,6 +305,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -331,6 +340,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
50, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
MGTURRET_RANGE, //int turretRange;
MGTURRET_REPEAT, //int turretFireSpeed;
@@ -363,6 +373,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
150, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
TESLAGEN_RANGE, //int turretRange;
TESLAGEN_REPEAT, //int turretFireSpeed;
@@ -395,6 +406,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -428,6 +440,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -460,6 +473,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -492,6 +506,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
-1, //int nextthink;
+ 10000, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -524,6 +539,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qtrue, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -556,6 +572,7 @@ buildableAttributes_t bg_buildableList[ ] =
( 1 << WP_HBUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
100, //int nextthink;
+ 10000, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
0, //int turretFireSpeed;
@@ -980,6 +997,26 @@ int BG_FindNextThinkForBuildable( int bclass )
/*
==============
+BG_FindBuildTimeForBuildable
+==============
+*/
+int BG_FindBuildTimeForBuildable( int bclass )
+{
+ int i;
+
+ for( i = 0; i < bg_numBuildables; i++ )
+ {
+ if( bg_buildableList[ i ].buildNum == bclass )
+ {
+ return bg_buildableList[ i ].buildTime;
+ }
+ }
+
+ return 10000;
+}
+
+/*
+==============
BG_FindUsableForBuildable
==============
*/
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index db9e8569..4ed62ec7 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -426,6 +426,10 @@ typedef enum
BIT_NUM_TEAMS
} buildableTeam_t;
+#define B_HEALTH_BITS 5
+#define B_HEALTH_SCALE (float)((1<<B_HEALTH_BITS)-1)
+
+#define B_SPAWNED_TOGGLEBIT 0x00000020
#define B_POWERED_TOGGLEBIT 0x00000040
#define B_DCCED_TOGGLEBIT 0x00000080
@@ -932,6 +936,7 @@ typedef struct
int idleAnim;
int nextthink;
+ int buildTime;
qboolean usable;
int turretRange;
@@ -1040,6 +1045,7 @@ int BG_FindTeamForBuildable( int bclass );
weapon_t BG_FindBuildWeaponForBuildable( int bclass );
int BG_FindAnimForBuildable( int bclass );
int BG_FindNextThinkForBuildable( int bclass );
+int BG_FindBuildTimeForBuildable( int bclass );
qboolean BG_FindUsableForBuildable( int bclass );
int BG_FindRangeForBuildable( int bclass );
int BG_FindFireSpeedForBuildable( int bclass );
diff --git a/src/game/g_active.c b/src/game/g_active.c
index ba1921ca..ec7a74fb 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1154,14 +1154,6 @@ void ClientThink_real( gentity_t *ent )
return;
}
- if( ( ( client->lastInfestTime +
- BG_FindEvolveTimeForClass( client->ps.stats[ STAT_PCLASS ] ) ) < level.time ) &&
- ( client->ps.stats[ STAT_STATE ] & SS_INFESTING ) )
- {
- client->ps.stats[ STAT_STATE ] &= ~SS_INFESTING;
- ClientSpawn( ent, client->infestBody );
- }
-
if( level.framenum > client->retriggerArmouryMenu && client->retriggerArmouryMenu )
{
G_TriggerMenu( client->ps.clientNum, MN_H_ARMOURY );
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 640fa752..224efc72 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -82,7 +82,8 @@ static qboolean findPower( gentity_t *self )
continue;
//if entity is a power item calculate the distance to it
- if( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER )
+ if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) &&
+ ent->spawned )
{
VectorSubtract( self->s.origin, ent->s.origin, temp_v );
distance = VectorLength( temp_v );
@@ -163,8 +164,8 @@ static qboolean findDCC( gentity_t *self )
if( !ent->classname || ent->s.eType != ET_BUILDABLE )
continue;
- //if entity is a power item calculate the distance to it
- if( ent->s.modelindex == BA_H_DCC )
+ //if entity is a dcc calculate the distance to it
+ if( ent->s.modelindex == BA_H_DCC && ent->spawned )
{
VectorSubtract( self->s.origin, ent->s.origin, temp_v );
distance = VectorLength( temp_v );
@@ -231,7 +232,8 @@ static qboolean findCreep( gentity_t *self )
if( !ent->classname || ent->s.eType != ET_BUILDABLE )
continue;
- if( ent->s.modelindex == BA_A_SPAWN || ent->s.modelindex == BA_A_OVERMIND )
+ if( ( ent->s.modelindex == BA_A_SPAWN || ent->s.modelindex == BA_A_OVERMIND ) &&
+ ent->spawned )
{
VectorSubtract( self->s.origin, ent->s.origin, temp_v );
distance = VectorLength( temp_v );
@@ -470,27 +472,30 @@ void ASpawn_Think( gentity_t *self )
trace_t tr;
float displacement;
- VectorSet( mins, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX );
- VectorSet( maxs, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX );
-
- VectorCopy( self->s.origin, origin );
- displacement = ( self->r.maxs[ 2 ] + MAX_ALIEN_BBOX ) * M_ROOT3 + 1.0f;
- VectorMA( origin, displacement, self->s.origin2, origin );
-
- //only suicide if at rest
- if( self->s.groundEntityNum )
+ if( self->spawned )
{
- trap_Trace( &tr, origin, mins, maxs, origin, self->s.number, MASK_SHOT );
- ent = &g_entities[ tr.entityNum ];
+ VectorSet( mins, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX );
+ VectorSet( maxs, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX );
- if( ent->s.eType == ET_BUILDABLE || ent->s.number == ENTITYNUM_WORLD )
+ VectorCopy( self->s.origin, origin );
+ displacement = ( self->r.maxs[ 2 ] + MAX_ALIEN_BBOX ) * M_ROOT3 + 1.0f;
+ VectorMA( origin, displacement, self->s.origin2, origin );
+
+ //only suicide if at rest
+ if( self->s.groundEntityNum )
{
- G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
- return;
- }
+ trap_Trace( &tr, origin, mins, maxs, origin, self->s.number, MASK_SHOT );
+ ent = &g_entities[ tr.entityNum ];
+
+ if( ent->s.eType == ET_BUILDABLE || ent->s.number == ENTITYNUM_WORLD )
+ {
+ G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE );
+ return;
+ }
- if( ent->s.eType == ET_CORPSE )
- G_FreeEntity( ent ); //quietly remove
+ if( ent->s.eType == ET_CORPSE )
+ G_FreeEntity( ent ); //quietly remove
+ }
}
creepSlow( self->s.modelindex, self->s.origin );
@@ -538,7 +543,7 @@ void AOvermind_Think( gentity_t *self )
VectorAdd( self->s.origin, range, maxs );
VectorSubtract( self->s.origin, range, mins );
- if( self->health > 0 )
+ if( self->spawned && ( self->health > 0 ) )
{
//do some damage
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
@@ -676,23 +681,26 @@ damage function for Alien Acid Tube
*/
void AAcidTube_Damage( gentity_t *self )
{
- if( !( self->s.eFlags & EF_FIRING ) )
+ if( self->spawned )
{
- self->s.eFlags |= EF_FIRING;
- G_AddEvent( self, EV_GIB_ALIEN, DirToByte( self->s.origin2 ) );
- }
-
- if( ( self->timestamp + ACIDTUBE_REPEAT ) > level.time )
- self->think = AAcidTube_Damage;
- else
- {
- self->think = AAcidTube_Think;
- self->s.eFlags &= ~EF_FIRING;
- }
+ if( !( self->s.eFlags & EF_FIRING ) )
+ {
+ self->s.eFlags |= EF_FIRING;
+ G_AddEvent( self, EV_GIB_ALIEN, DirToByte( self->s.origin2 ) );
+ }
+
+ if( ( self->timestamp + ACIDTUBE_REPEAT ) > level.time )
+ self->think = AAcidTube_Damage;
+ else
+ {
+ self->think = AAcidTube_Think;
+ self->s.eFlags &= ~EF_FIRING;
+ }
- //do some damage
- G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage,
- self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
+ //do some damage
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self->parent, self->splashDamage,
+ self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
+ }
creepSlow( self->s.modelindex, self->s.origin );
@@ -724,19 +732,22 @@ void AAcidTube_Think( gentity_t *self )
return;
}
- //do some damage
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( self->spawned )
{
- enemy = &g_entities[ entityList[ i ] ];
-
- if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ //do some damage
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- self->timestamp = level.time;
- self->think = AAcidTube_Damage;
- self->nextthink = level.time + 100;
- G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
- return;
+ enemy = &g_entities[ entityList[ i ] ];
+
+ if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ {
+ self->timestamp = level.time;
+ self->think = AAcidTube_Damage;
+ self->nextthink = level.time + 100;
+ G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ return;
+ }
}
}
@@ -763,37 +774,40 @@ void AHovel_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
vec3_t hovelOrigin, hovelAngles, inverseNormal;
- if( self->active )
- {
- //this hovel is in use
- G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_OCCUPIED );
- }
- else if( ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_A_B_BASE ) ||
- ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_A_B_LEV1 ) )
+ if( self->spawned )
{
- self->active = qtrue;
- G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ if( self->active )
+ {
+ //this hovel is in use
+ G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_OCCUPIED );
+ }
+ else if( ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_A_B_BASE ) ||
+ ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_A_B_LEV1 ) )
+ {
+ self->active = qtrue;
+ G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
- //prevent lerping
- activator->client->ps.eFlags ^= EF_TELEPORT_BIT;
-
- activator->client->sess.sessionTeam = TEAM_FREE;
- activator->client->ps.stats[ STAT_STATE ] |= SS_HOVELING;
- activator->client->infestBody = self;
- self->builder = activator;
+ //prevent lerping
+ activator->client->ps.eFlags ^= EF_TELEPORT_BIT;
+
+ activator->client->sess.sessionTeam = TEAM_FREE;
+ activator->client->ps.stats[ STAT_STATE ] |= SS_HOVELING;
+ activator->client->infestBody = self;
+ self->builder = activator;
- VectorCopy( self->s.pos.trBase, hovelOrigin );
- VectorMA( hovelOrigin, 128.0f, self->s.origin2, hovelOrigin );
+ VectorCopy( self->s.pos.trBase, hovelOrigin );
+ VectorMA( hovelOrigin, 128.0f, self->s.origin2, hovelOrigin );
- VectorCopy( self->s.origin2, inverseNormal );
- VectorInverse( inverseNormal );
- vectoangles( inverseNormal, hovelAngles );
+ VectorCopy( self->s.origin2, inverseNormal );
+ VectorInverse( inverseNormal );
+ vectoangles( inverseNormal, hovelAngles );
- VectorCopy( activator->s.pos.trBase, activator->client->hovelOrigin );
+ VectorCopy( activator->s.pos.trBase, activator->client->hovelOrigin );
- G_SetOrigin( activator, hovelOrigin );
- VectorCopy( hovelOrigin, activator->client->ps.origin );
- SetClientViewAngle( activator, hovelAngles );
+ G_SetOrigin( activator, hovelOrigin );
+ VectorCopy( hovelOrigin, activator->client->ps.origin );
+ SetClientViewAngle( activator, hovelAngles );
+ }
}
}
@@ -807,10 +821,13 @@ Think for alien hovel
*/
void AHovel_Think( gentity_t *self )
{
- if( self->active )
- G_setIdleBuildableAnim( self, BANIM_IDLE2 );
- else
- G_setIdleBuildableAnim( self, BANIM_IDLE1 );
+ if( self->spawned )
+ {
+ if( self->active )
+ G_setIdleBuildableAnim( self, BANIM_IDLE2 );
+ else
+ G_setIdleBuildableAnim( self, BANIM_IDLE1 );
+ }
creepSlow( self->s.modelindex, self->s.origin );
@@ -892,6 +909,9 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
int ammo, clips, maxClips;
gclient_t *client = other->client;
+ if( !self->spawned )
+ return;
+
if( !client )
return;
@@ -1056,17 +1076,20 @@ void ATrapper_Think( gentity_t *self )
return;
}
- //if the current target is not valid find a new one
- if( !adef_checktarget( self, self->enemy, range ) )
- adef_findenemy( self, range );
+ if( self->spawned )
+ {
+ //if the current target is not valid find a new one
+ if( !adef_checktarget( self, self->enemy, range ) )
+ adef_findenemy( self, range );
- //if a new target cannot be found don't do anything
- if( !self->enemy )
- return;
-
- //if we are pointing at our target and we can fire shoot it
- if( self->count < level.time )
- adef_fireonenemy( self, firespeed );
+ //if a new target cannot be found don't do anything
+ if( !self->enemy )
+ return;
+
+ //if we are pointing at our target and we can fire shoot it
+ if( self->count < level.time )
+ adef_fireonenemy( self, firespeed );
+ }
}
@@ -1087,15 +1110,18 @@ void HRpt_Think( gentity_t *self )
int i;
qboolean reactor = qfalse;
gentity_t *ent;
-
- //iterate through entities
- for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+
+ if( self->spawned )
{
- if( !ent->classname || ent->s.eType != ET_BUILDABLE )
- continue;
+ //iterate through entities
+ for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( !ent->classname || ent->s.eType != ET_BUILDABLE )
+ continue;
- if( ent->s.modelindex == BA_H_REACTOR )
- reactor = qtrue;
+ if( ent->s.modelindex == BA_H_REACTOR )
+ reactor = qtrue;
+ }
}
self->powered = reactor;
@@ -1117,6 +1143,9 @@ void HRpt_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
playerState_t *ps = &activator->client->ps;
+ if( !self->spawned )
+ return;
+
if( activator->client->lastRefilTime + ENERGY_REFIL_TIME > level.time )
return;
@@ -1162,14 +1191,18 @@ Called when a human activates an Armoury
*/
void HArmoury_Activate( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- //only humans can activate this
- if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS ) return;
-
- //if this is powered then call the armoury menu
- if( self->powered )
- G_TriggerMenu( activator->client->ps.clientNum, MN_H_ARMOURY );
- else
- G_TriggerMenu( activator->client->ps.clientNum, MN_H_NOPOWER );
+ if( self->spawned )
+ {
+ //only humans can activate this
+ if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ return;
+
+ //if this is powered then call the armoury menu
+ if( self->powered )
+ G_TriggerMenu( activator->client->ps.clientNum, MN_H_ARMOURY );
+ else
+ G_TriggerMenu( activator->client->ps.clientNum, MN_H_NOPOWER );
+ }
}
/*
@@ -1203,14 +1236,18 @@ Called when a human activates a Bank
*/
void HBank_Activate( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- //only humans can activate this
- if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS ) return;
-
- //if this is powered then call the bank menu
- if( self->powered )
- G_TriggerMenu( activator->client->ps.clientNum, MN_H_BANK );
- else
- G_TriggerMenu( activator->client->ps.clientNum, MN_H_NOPOWER );
+ if( self->spawned )
+ {
+ //only humans can activate this
+ if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
+ return;
+
+ //if this is powered then call the bank menu
+ if( self->powered )
+ G_TriggerMenu( activator->client->ps.clientNum, MN_H_BANK );
+ else
+ G_TriggerMenu( activator->client->ps.clientNum, MN_H_NOPOWER );
+ }
}
/*
@@ -1272,6 +1309,8 @@ void HMedistat_Think( gentity_t *self )
int healCount = 0;
int maxclients;
+ self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
+
//make sure we have power
if( !( self->powered = findPower( self ) ) )
{
@@ -1279,53 +1318,54 @@ void HMedistat_Think( gentity_t *self )
return;
}
- maxclients = MAX_MEDISTAT_CLIENTS;
-
- VectorAdd( self->s.origin, self->r.maxs, maxs );
- VectorAdd( self->s.origin, self->r.mins, mins );
-
- mins[ 2 ] += fabs( self->r.mins[ 2 ] ) + self->r.maxs[ 2 ];
- maxs[ 2 ] += 60; //player height
-
- //if active use the healing idle
- if( self->active )
- G_setIdleBuildableAnim( self, BANIM_IDLE2 );
-
- //do some healage
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( self->spawned )
{
- player = &g_entities[ entityList[ i ] ];
+ maxclients = MAX_MEDISTAT_CLIENTS;
- if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
+ VectorAdd( self->s.origin, self->r.maxs, maxs );
+ VectorAdd( self->s.origin, self->r.mins, mins );
+
+ mins[ 2 ] += fabs( self->r.mins[ 2 ] ) + self->r.maxs[ 2 ];
+ maxs[ 2 ] += 60; //player height
+
+ //if active use the healing idle
+ if( self->active )
+ G_setIdleBuildableAnim( self, BANIM_IDLE2 );
+
+ //do some healage
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
- player->client->ps.pm_type != PM_DEAD &&
- healCount < maxclients )
+ player = &g_entities[ entityList[ i ] ];
+
+ if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS )
{
- healCount++;
- player->health++;
-
- //start the heal anim
- if( !self->active )
+ if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ player->client->ps.pm_type != PM_DEAD &&
+ healCount < maxclients )
{
- G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
- self->active = qtrue;
+ healCount++;
+ player->health++;
+
+ //start the heal anim
+ if( !self->active )
+ {
+ G_setBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ self->active = qtrue;
+ }
}
}
}
- }
- //nothing left to heal so go back to idling
- if( healCount == 0 && self->active )
- {
- G_setBuildableAnim( self, BANIM_CONSTRUCT2, qtrue );
- G_setIdleBuildableAnim( self, BANIM_IDLE1 );
-
- self->active = qfalse;
+ //nothing left to heal so go back to idling
+ if( healCount == 0 && self->active )
+ {
+ G_setBuildableAnim( self, BANIM_CONSTRUCT2, qtrue );
+ G_setIdleBuildableAnim( self, BANIM_IDLE1 );
+
+ self->active = qfalse;
+ }
}
-
- self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -1607,40 +1647,43 @@ void HDef_Think( gentity_t *self )
return;
}
- //find a dcc for self
- self->dcced = findDCC( self );
-
- //if the current target is not valid find a new one
- if( !HDef_CheckTarget( self, self->enemy, range ) )
+ if( self->spawned )
{
- if( self->enemy )
- self->enemy->targeted = NULL;
+ //find a dcc for self
+ self->dcced = findDCC( self );
+
+ //if the current target is not valid find a new one
+ if( !HDef_CheckTarget( self, self->enemy, range ) )
+ {
+ if( self->enemy )
+ self->enemy->targeted = NULL;
- HDef_FindEnemy( self, range );
- }
+ HDef_FindEnemy( self, range );
+ }
- //if a new target cannot be found don't do anything
- if( !self->enemy )
- return;
-
- self->enemy->targeted = self;
+ //if a new target cannot be found don't do anything
+ if( !self->enemy )
+ return;
+
+ self->enemy->targeted = self;
- //if we are pointing at our target and we can fire shoot it
- switch( self->s.modelindex )
- {
- case BA_H_MGTURRET:
- if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) )
- HMGTurret_FireOnEnemy( self, firespeed );
- break;
-
- case BA_H_TESLAGEN:
- if( self->count < level.time )
- HTeslaGen_FireOnEnemy( self, firespeed );
- break;
+ //if we are pointing at our target and we can fire shoot it
+ switch( self->s.modelindex )
+ {
+ case BA_H_MGTURRET:
+ if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) )
+ HMGTurret_FireOnEnemy( self, firespeed );
+ break;
+
+ case BA_H_TESLAGEN:
+ if( self->count < level.time )
+ HTeslaGen_FireOnEnemy( self, firespeed );
+ break;
- default:
- Com_Printf( S_COLOR_YELLOW "WARNING: Unknown turret type in think\n" );
- break;
+ default:
+ Com_Printf( S_COLOR_YELLOW "WARNING: Unknown turret type in think\n" );
+ break;
+ }
}
}
@@ -1970,6 +2013,10 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin
G_setIdleBuildableAnim( built, BG_FindAnimForBuildable( buildable ) );
built->nextthink = BG_FindNextThinkForBuildable( buildable );
+
+ built->takedamage = qfalse;
+ built->spawned = qfalse;
+ built->buildTime = level.time;
//things that vary for each buildable that aren't in the dbase
switch( buildable )
@@ -2074,7 +2121,6 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin
break;
}
- built->takedamage = qtrue;
built->s.number = built - g_entities;
built->r.contents = CONTENTS_BODY;
built->clipmask = MASK_PLAYERSOLID;
@@ -2109,7 +2155,7 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin
VectorSet( normal, 0.0f, 0.0f, 1.0f );
built->s.generic1 = (int)( ( (float)built->health /
- (float)BG_FindHealthForBuildable( buildable ) ) * 63.0f );
+ (float)BG_FindHealthForBuildable( buildable ) ) * B_HEALTH_SCALE );
if( built->s.generic1 < 0 )
built->s.generic1 = 0;
@@ -2120,6 +2166,8 @@ gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin
if( built->dcced = findDCC( built ) )
built->s.generic1 |= B_DCCED_TOGGLEBIT;
+ built->s.generic1 &= ~B_SPAWNED_TOGGLEBIT;
+
VectorCopy( normal, built->s.origin2 );
G_AddEvent( built, EV_BUILD_CONSTRUCT, BANIM_CONSTRUCT1 );
@@ -2224,16 +2272,21 @@ void FinishSpawningBuildable( gentity_t *ent )
built = G_buildItem( ent, buildable, ent->s.pos.trBase, ent->s.angles );
G_FreeEntity( ent );
+ built->takedamage = qtrue;
+ built->spawned = qtrue; //map entities are already spawned
+ built->s.generic1 |= B_SPAWNED_TOGGLEBIT;
+
// drop to floor
if( buildable != BA_NONE && BG_FindTrajectoryForBuildable( buildable ) == TR_BUOYANCY )
- VectorSet( dest, built->s.origin[0], built->s.origin[1], built->s.origin[2] + 4096 );
+ VectorSet( dest, built->s.origin[ 0 ], built->s.origin[ 1 ], built->s.origin[ 2 ] + 4096 );
else
- VectorSet( dest, built->s.origin[0], built->s.origin[1], built->s.origin[2] - 4096 );
+ VectorSet( dest, built->s.origin[ 0 ], built->s.origin[ 1 ], built->s.origin[ 2 ] - 4096 );
trap_Trace( &tr, built->s.origin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask );
+
if( tr.startsolid )
{
- G_Printf ("FinishSpawningBuildable: %s startsolid at %s\n", built->classname, vtos(built->s.origin));
+ G_Printf( "FinishSpawningBuildable: %s startsolid at %s\n", built->classname, vtos( built->s.origin ) );
G_FreeEntity( built );
return;
}
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 173bcd54..0d40f38c 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -293,6 +293,9 @@ gentity_t *SelectAlienSpawnPoint( void )
while( ( spot = G_Find( spot, FOFS( classname ),
BG_FindEntityNameForBuildable( BA_A_SPAWN ) ) ) != NULL )
{
+ if( !spot->spawned )
+ continue;
+
if( spot->health <= 0 )
continue;
@@ -354,6 +357,9 @@ gentity_t *SelectHumanSpawnPoint( void )
while( ( spot = G_Find( spot, FOFS( classname ),
BG_FindEntityNameForBuildable( BA_H_SPAWN ) ) ) != NULL )
{
+ if( !spot->spawned )
+ continue;
+
if( spot->health <= 0 )
continue;
@@ -787,7 +793,7 @@ void respawn( gentity_t *ent )
SpawnCorpse( ent );
//TA: Clients can't respawn - they must go thru the class cmd
- ClientSpawn( ent, NULL );
+ ClientSpawn( ent, NULL, NULL, NULL );
//FIXME: need different spawn effects for different teams
@@ -1232,7 +1238,7 @@ void ClientBegin( int clientNum )
// locate ent at a spawn point
- ClientSpawn( ent, NULL );
+ ClientSpawn( ent, NULL, NULL, NULL );
if( client->sess.sessionTeam != TEAM_SPECTATOR )
{
@@ -1258,7 +1264,7 @@ after the first ClientBegin, and after each respawn
Initializes all non-persistant parts of playerState
============
*/
-void ClientSpawn( gentity_t *ent, gentity_t *spawn )
+void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles )
{
int index;
vec3_t spawn_origin, spawn_angles;
@@ -1266,15 +1272,15 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn )
int i;
clientPersistant_t saved;
clientSession_t savedSess;
- int persistant[MAX_PERSISTANT];
+ int persistant[ MAX_PERSISTANT ];
gentity_t *spawnPoint;
int flags;
int savedPing;
int ammoIndex, ammoSubIndex;
int teamLocal;
int eventSequence;
- char userinfo[MAX_INFO_STRING];
- vec3_t classMins, classMaxs, up = { 0, 0, 1 };
+ char userinfo[ MAX_INFO_STRING ];
+ vec3_t classMins, classMaxs, up = { 0.0f, 0.0f, 1.0f };
int ammo, clips, maxClips;
weapon_t weapon;
float hModifier;
@@ -1286,17 +1292,23 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn )
teamLocal = client->pers.pteam;
//TA: only start client if chosen a class and joined a team
- if( client->pers.pclass == 0 && teamLocal == 0 )
+ if( client->pers.pclass == PCL_NONE && teamLocal == PTE_NONE )
{
client->sess.sessionTeam = TEAM_SPECTATOR;
client->sess.spectatorState = SPECTATOR_FREE;
}
- else if( client->pers.pclass == 0 )
+ else if( client->pers.pclass == PCL_NONE )
{
client->sess.sessionTeam = TEAM_SPECTATOR;
client->sess.spectatorState = SPECTATOR_LOCKED;
}
+ if( origin != NULL )
+ VectorCopy( origin, spawn_origin );
+
+ if( angles != NULL )
+ VectorCopy( angles, spawn_angles );
+
// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
@@ -1311,29 +1323,17 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn )
}
else
{
- //this is an infest spawn
- if( spawn )
+ if( spawn == NULL )
{
- vec3_t prevMins, prevMaxs;
-
- //spawn as new alien
- VectorCopy( spawn->s.pos.trBase, spawn_origin );
- VectorCopy( spawn->s.apos.trBase, spawn_angles );
-
- spawnPoint = spawn;
+ G_Error( "ClientSpawn: spawn is NULL\n" );
+ return;
}
- else
- {
- // don't spawn near existing origin if possible
- spawnPoint = SelectTremulousSpawnPoint( teamLocal, spawn_origin, spawn_angles );
- if( spawnPoint == NULL )
- {
- trap_SendServerCommand( ent-g_entities, va("print \"No suitable spawns available\n\"" ) );
- return;
- }
-
- //start spawn animation on egg
+ spawnPoint = spawn;
+
+ if( ent != spawn )
+ {
+ //start spawn animation on spawnPoint
G_setBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue );
}
}
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 6c73b863..0f31c7e7 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -366,7 +366,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.pclass = 0;
- ClientSpawn( ent, NULL );
+ ClientSpawn( ent, NULL, NULL, NULL );
}
//update ClientInfo
@@ -956,7 +956,8 @@ void Cmd_Class_f( gentity_t *ent )
char s[ MAX_TOKEN_CHARS ];
qboolean dontSpawn = qfalse;
int clientNum;
- gentity_t *body, *victim;
+ gentity_t *spawn;
+ vec3_t spawn_origin, spawn_angles;
vec3_t distance;
vec3_t up = { 0.0f, 0.0f, 1.0f };
int length = 4096;
@@ -1029,7 +1030,7 @@ void Cmd_Class_f( gentity_t *ent )
ClientUserinfoChanged( clientNum );
VectorCopy( infestOrigin, ent->s.pos.trBase );
- ClientSpawn( ent, ent );
+ ClientSpawn( ent, ent, ent->s.pos.trBase, ent->s.apos.trBase );
return;
}
else
@@ -1048,14 +1049,7 @@ void Cmd_Class_f( gentity_t *ent )
}
else
{
- //sanity check
- if( level.numAlienSpawns <= 0 )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"No suitable spawns available\n\"" ) );
- return;
- }
-
- //spawing from an egg
+ //spawning from an egg
ent->client->pers.pclass = BG_FindClassNumForName( s );
if( ent->client->pers.pclass != PCL_NONE )
@@ -1065,10 +1059,19 @@ void Cmd_Class_f( gentity_t *ent )
if( allowedClasses[ i ] == ent->client->pers.pclass &&
BG_FindStagesForClass( ent->client->pers.pclass, g_alienStage.integer ) )
{
- ent->client->sess.sessionTeam = TEAM_FREE;
- ClientUserinfoChanged( clientNum );
- ClientSpawn( ent, NULL );
- return;
+ if( ( spawn = SelectTremulousSpawnPoint( ent->client->pers.pteam, 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;
+ }
}
}
@@ -1084,13 +1087,6 @@ void Cmd_Class_f( gentity_t *ent )
}
else if( ent->client->pers.pteam == PTE_HUMANS )
{
- //sanity check
- if( level.numHumanSpawns <= 0 )
- {
- trap_SendServerCommand( ent-g_entities, va( "print \"No suitable spawns available\n\"" ) );
- return;
- }
-
//humans cannot use this command whilst alive
if( ent->client->ps.stats[ STAT_PCLASS ] != PCL_NONE )
{
@@ -1112,16 +1108,25 @@ void Cmd_Class_f( gentity_t *ent )
return;
}
- ent->client->sess.sessionTeam = TEAM_FREE;
- ClientUserinfoChanged( clientNum );
- ClientSpawn( ent, NULL );
+ if( ( spawn = SelectTremulousSpawnPoint( ent->client->pers.pteam, 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;
+ }
}
else if( ent->client->pers.pteam == PTE_NONE )
{
//can't use this command unless on a team
ent->client->pers.pclass = PCL_NONE;
ent->client->sess.sessionTeam = TEAM_FREE;
- ClientSpawn( ent, NULL );
+ ClientSpawn( ent, NULL, NULL, NULL );
trap_SendServerCommand( ent-g_entities, va( "print \"Join a team first\n\"" ) );
}
}
@@ -1157,7 +1162,7 @@ void Cmd_Destroy_f( gentity_t *ent, qboolean deconstruct )
{
if( ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- G_AddEvent( ent, EV_BUILD_DELAY, 0 );
+ G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
return;
}
@@ -1288,7 +1293,7 @@ void Cmd_Buy_f( gentity_t *ent )
if( armouryEntity->s.eType != ET_BUILDABLE )
continue;
- if( armouryEntity->s.modelindex == BA_H_ARMOURY )
+ if( armouryEntity->s.modelindex == BA_H_ARMOURY && armouryEntity->spawned )
{
VectorSubtract( ent->s.pos.trBase, armouryEntity->s.origin, distance );
if( VectorLength( distance ) <= 100 )
@@ -1502,7 +1507,7 @@ void Cmd_Sell_f( gentity_t *ent )
if( armouryEntity->s.eType != ET_BUILDABLE )
continue;
- if( armouryEntity->s.modelindex == BA_H_ARMOURY )
+ if( armouryEntity->s.modelindex == BA_H_ARMOURY && armouryEntity->spawned )
{
VectorSubtract( ent->s.pos.trBase, armouryEntity->s.origin, distance );
if( VectorLength( distance ) <= 100 )
@@ -1590,7 +1595,7 @@ void Cmd_Deposit_f( gentity_t *ent )
if( bankEntity->s.eType != ET_BUILDABLE )
continue;
- if( bankEntity->s.modelindex == BA_H_BANK )
+ if( bankEntity->s.modelindex == BA_H_BANK && bankEntity->spawned )
{
VectorSubtract( ent->s.pos.trBase, bankEntity->s.origin, distance );
if( VectorLength( distance ) <= 100 )
@@ -1652,7 +1657,7 @@ void Cmd_Withdraw_f( gentity_t *ent )
if( bankEntity->s.eType != ET_BUILDABLE )
continue;
- if( bankEntity->s.modelindex == BA_H_BANK )
+ if( bankEntity->s.modelindex == BA_H_BANK && bankEntity->spawned )
{
VectorSubtract( ent->s.pos.trBase, bankEntity->s.origin, distance );
if( VectorLength( distance ) <= 100 )
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 8865bf15..471b1b91 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -178,6 +178,8 @@ struct gentity_s
int builtBy; //TA: clientNum of person that built this
gentity_t *dccNode; //TA: controlling dcc
qboolean dcced; //TA: controlled by a dcc or not?
+ qboolean spawned; //TA: whether or not this buildable has finished spawning
+ int buildTime; //TA: when this buildable was built
int time1000; //TA: timer evaluated every second
int credits[ MAX_CLIENTS ]; //TA: human credits for each client
@@ -664,11 +666,12 @@ qboolean CheckPounceAttack( gentity_t *ent );
//
team_t TeamCount( int ignoreClientNum, int team );
void SetClientViewAngle( gentity_t *ent, vec3_t angle );
+gentity_t *SelectTremulousSpawnPoint( int team, vec3_t origin, vec3_t angles );
gentity_t *SelectSpawnPoint( vec3_t avoidPoint, vec3_t origin, vec3_t angles );
void SpawnCorpse( gentity_t *ent );
void respawn( gentity_t *ent );
void BeginIntermission( void );
-void ClientSpawn( gentity_t *ent, gentity_t *spawn );
+void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles );
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod );
qboolean SpotWouldTelefrag( gentity_t *spot );
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 5e472b44..bc74cfe9 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -1539,7 +1539,7 @@ void G_RunFrame( int levelTime )
G_Physics( ent, msec );
continue;
}
-
+
if( ent->s.eType == ET_MOVER )
{
G_RunMover( ent );
diff --git a/src/game/g_physics.c b/src/game/g_physics.c
index 7dcfa981..e5e69b19 100644
--- a/src/game/g_physics.c
+++ b/src/game/g_physics.c
@@ -87,7 +87,17 @@ void G_Physics( gentity_t *ent, int msec )
//pack health, power and dcc
if( ent->s.eType == ET_BUILDABLE )
{
- ent->s.generic1 = (int)( ( (float)ent->health / (float)bHealth ) * 63.0f );
+ //toggle spawned flag for buildables
+ if( !ent->spawned )
+ {
+ if( ent->buildTime + BG_FindBuildTimeForBuildable( ent->s.modelindex ) < level.time )
+ {
+ ent->takedamage = qtrue;
+ ent->spawned = qtrue;
+ }
+ }
+
+ ent->s.generic1 = (int)( ( (float)ent->health / (float)bHealth ) * B_HEALTH_SCALE );
if( ent->s.generic1 < 0 )
ent->s.generic1 = 0;
@@ -98,6 +108,9 @@ void G_Physics( gentity_t *ent, int msec )
if( ent->dcced )
ent->s.generic1 |= B_DCCED_TOGGLEBIT;
+ if( ent->spawned )
+ ent->s.generic1 |= B_SPAWNED_TOGGLEBIT;
+
ent->time1000 += msec;
if( ent->time1000 >= 1000 )
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 194d022b..2d9d0744 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -465,7 +465,7 @@ void cancelBuildFire( gentity_t *ent )
{
if( ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- G_AddPredictableEvent( ent, EV_BUILD_DELAY, 0 );
+ G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
return;
}
@@ -487,7 +487,7 @@ void buildFire( gentity_t *ent, dynMenu_t menu )
{
if( ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- G_AddPredictableEvent( ent, EV_BUILD_DELAY, 0 );
+ G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum );
return;
}