diff options
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/bg_misc.c | 37 | ||||
-rw-r--r-- | src/game/bg_public.h | 6 | ||||
-rw-r--r-- | src/game/g_active.c | 8 | ||||
-rw-r--r-- | src/game/g_buildable.c | 415 | ||||
-rw-r--r-- | src/game/g_client.c | 56 | ||||
-rw-r--r-- | src/game/g_cmds.c | 67 | ||||
-rw-r--r-- | src/game/g_local.h | 5 | ||||
-rw-r--r-- | src/game/g_main.c | 2 | ||||
-rw-r--r-- | src/game/g_physics.c | 15 | ||||
-rw-r--r-- | src/game/g_weapon.c | 4 |
10 files changed, 362 insertions, 253 deletions
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; } |