summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/bg_misc.c1
-rw-r--r--src/game/bg_public.h3
-rw-r--r--src/game/g_active.c15
-rw-r--r--src/game/g_buildable.c118
-rw-r--r--src/game/g_weapon.c8
5 files changed, 108 insertions, 37 deletions
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 2319f31f..85c1f47a 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -5166,6 +5166,7 @@ void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
//so buildings drop to floor
VectorMA( targetOrigin, -128, playerNormal, targetOrigin );
+ // The mask is MASK_DEADSOLID on purpose to avoid collisions with other entities
(*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_DEADSOLID );
VectorCopy( tr->endpos, entityOrigin );
VectorMA( entityOrigin, 0.1f, playerNormal, outOrigin );
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 68217cf0..ca87da50 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -433,10 +433,9 @@ typedef enum
BIT_NUM_TEAMS
} buildableTeam_t;
-#define B_HEALTH_BITS 11
+#define B_HEALTH_BITS 12
#define B_HEALTH_MASK ((1<<B_HEALTH_BITS)-1)
-#define B_REMOVED_TOGGLEBIT 0x00000800
#define B_MARKED_TOGGLEBIT 0x00001000
#define B_SPAWNED_TOGGLEBIT 0x00002000
#define B_POWERED_TOGGLEBIT 0x00004000
diff --git a/src/game/g_active.c b/src/game/g_active.c
index ce60daff..17f66352 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -513,6 +513,7 @@ void ClientTimerActions( gentity_t *ent, int msec )
gclient_t *client;
usercmd_t *ucmd;
int aForward, aRight;
+ int i;
ucmd = &ent->client->pers.cmd;
@@ -675,6 +676,20 @@ void ClientTimerActions( gentity_t *ent, int msec )
client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT;
else
client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT;
+
+ // Let the client know which buildables will be removed by building
+ for( i = 0; i < MAX_MISC; i++ )
+ {
+ if( i < level.numBuildablesForRemoval )
+ client->ps.misc[ i ] = level.markedBuildables[ i ]->s.number;
+ else
+ client->ps.misc[ i ] = 0;
+ }
+ }
+ else
+ {
+ for( i = 0; i < MAX_MISC; i++ )
+ client->ps.misc[ i ] = 0;
}
//update build timer
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 22a37455..2b9fa394 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -2462,15 +2462,6 @@ void G_BuildableThink( gentity_t *ent, int msec )
if( ent->deconstruct )
ent->s.generic1 |= B_MARKED_TOGGLEBIT;
- for( i = 0; i < level.numBuildablesForRemoval; i++ )
- {
- if( ent->s.number == level.markedBuildables[ i ]->s.number )
- {
- ent->s.generic1 |= B_REMOVED_TOGGLEBIT;
- break;
- }
- }
-
ent->time1000 += msec;
if( ent->time1000 >= 1000 )
@@ -2687,18 +2678,22 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
qboolean collision = qfalse;
int collisionCount = 0;
itemBuildError_t bpError;
+ buildable_t spawn;
+ int spawnCount = 0;
if( team == BIT_ALIENS )
{
remainingBP = level.alienBuildPoints;
remainingSpawns = level.numAlienSpawns;
bpError = IBE_NOASSERT;
+ spawn = BA_A_SPAWN;
}
else if( team == BIT_HUMANS )
{
remainingBP = level.humanBuildPoints;
remainingSpawns = level.numHumanSpawns;
bpError = IBE_NOPOWER;
+ spawn = BA_H_SPAWN;
}
else
Com_Error( ERR_FATAL, "team is %d\n", team );
@@ -2708,8 +2703,18 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
{
if( remainingBP - buildPoints < 0 )
return bpError;
- else
- return IBE_NONE;
+
+ // Check for buildable<->buildable collisions
+ for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+
+ if( G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->s.origin ) )
+ return IBE_NOROOM;
+ }
+
+ return IBE_NONE;
}
// Set buildPoints to the number extra that are required
@@ -2720,9 +2725,25 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
// Build a list of buildable entities
for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
- if( ( collision = G_BuildablesIntersect( buildable, origin,
- ent->s.modelindex, ent->s.origin ) ) )
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+
+ collision = G_BuildablesIntersect( buildable, origin, ent->s.modelindex, ent->s.origin );
+
+ if( collision )
+ {
+ // Don't allow replacements at all
+ if( g_markDeconstruct.integer == 1 )
+ return IBE_NOROOM;
+
+ // Only allow replacements of the same type
+ if( g_markDeconstruct.integer == 2 && ent->s.modelindex != buildable )
+ return IBE_NOROOM;
+
+ // Any other setting means anything goes
+
collisionCount++;
+ }
if( !ent->inuse )
continue;
@@ -2737,13 +2758,6 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
if( ent->biteam != team )
continue;
- // Prevent destruction of the last spawn
- if( remainingSpawns <= 1 )
- {
- if( ent->s.modelindex == BA_A_SPAWN || ent->s.modelindex == BA_H_SPAWN )
- continue;
- }
-
// If it's a unique buildable, it can only be replaced by the same type
if( BG_FindUniqueTestForBuildable( ent->s.modelindex ) &&
ent->s.modelindex != buildable )
@@ -2753,15 +2767,20 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
{
level.markedBuildables[ numBuildables++ ] = ent;
- // Collided with something, so we definitely have to remove it
- // It will always end up at the front of the removal list, so
- // incrementing numBuildablesForRemoval is sufficient
if( collision )
{
+ // Collided with something, so we definitely have to remove it
+ // It will always end up at the front of the removal list, so
+ // incrementing numBuildablesForRemoval is sufficient
collisionCount--;
pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
level.numBuildablesForRemoval++;
}
+ else if( BG_FindUniqueTestForBuildable( ent->s.modelindex ) )
+ {
+ pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
+ level.numBuildablesForRemoval++;
+ }
}
}
@@ -2787,15 +2806,44 @@ static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
pointsYielded += BG_FindBuildPointsForBuildable( ent->s.modelindex );
}
+ for( i = 0; i < level.numBuildablesForRemoval; i++ )
+ {
+ if( level.markedBuildables[ i ]->s.modelindex == spawn )
+ spawnCount++;
+ }
+
+ // Make sure we're not removing the last spawn
+ if( ( remainingSpawns - spawnCount ) < 1 )
+ return bpError;
+
// Not enough points yielded
if( pointsYielded < buildPoints )
- {
- level.numBuildablesForRemoval = 0;
return bpError;
- }
else
- {
return IBE_NONE;
+}
+
+/*
+================
+G_SetBuildableLinkState
+
+Links or unlinks all the buildable entities
+================
+*/
+static void G_SetBuildableLinkState( qboolean link )
+{
+ int i;
+ gentity_t *ent;
+
+ for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ )
+ {
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+
+ if( link )
+ trap_LinkEntity( ent );
+ else
+ trap_UnlinkEntity( ent );
}
}
@@ -2821,12 +2869,14 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
playerState_t *ps = &ent->client->ps;
int buildPoints;
+ // Stop all buildables from interacting with traces
+ G_SetBuildableLinkState( qfalse );
+
BG_FindBBoxForBuildable( buildable, mins, maxs );
BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, trap_Trace, entity_origin, angles, &tr1 );
-
- trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_DEADSOLID );
- trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_DEADSOLID );
+ trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID );
+ trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID );
VectorCopy( entity_origin, origin );
@@ -2997,7 +3047,13 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
//this item does not fit here
if( reason == IBE_NONE && ( tr2.fraction < 1.0 || tr3.fraction < 1.0 ) )
- return IBE_NOROOM;
+ reason = IBE_NOROOM;
+
+ if( reason != IBE_NONE )
+ level.numBuildablesForRemoval = 0;
+
+ // Relink buildables
+ G_SetBuildableLinkState( qtrue );
return reason;
}
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 9d015e8b..cfc7cc1f 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -42,8 +42,8 @@ void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
{
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- if( weapon == WP_NONE
- || !BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ))
+ if( weapon == WP_NONE ||
+ !BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ))
{
//switch to the first non blaster weapon
for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
@@ -64,8 +64,8 @@ void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon )
}
else
ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon;
-
- // force this here to prevent flamer effect from continuing
+
+ // force this here to prevent flamer effect from continuing
ent->client->ps.generic1 = WPM_NOTFIRING;
ent->client->ps.weapon = ent->client->ps.persistant[ PERS_NEWWEAPON ];