summaryrefslogtreecommitdiff
path: root/src/game/g_buildable.c
diff options
context:
space:
mode:
authorChristopher Schwarz <lakitu7@gmail.com>2010-05-23 17:33:08 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:17:37 +0000
commit034057319870cc058097190434b1199cec206187 (patch)
tree6ada72295b2ceed815e6f1b7d3baa5fff067ea23 /src/game/g_buildable.c
parentc1eebf26871feec7a56eea2d2184ca06b596b30d (diff)
* (bug 3291) Add /buildlog and /revert commands to combat grief building (Undeference, Rezyn, and originally Benmachine)
Diffstat (limited to 'src/game/g_buildable.c')
-rw-r--r--src/game/g_buildable.c225
1 files changed, 216 insertions, 9 deletions
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 0ec5f65c..5579be34 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -2474,15 +2474,15 @@ void HTeslaGen_Think( gentity_t *self )
/*
============
-G_QueueBuildPoints
+G_QueueValue
============
*/
-void G_QueueBuildPoints( gentity_t *self )
+
+static int G_QueueValue( gentity_t *self )
{
- gentity_t *powerEntity;
int i;
int damageTotal = 0;
- int queuePoints = 0;
+ int queuePoints;
double queueFraction = 0;
for( i = 0; i < level.maxclients; i++ )
@@ -2501,6 +2501,20 @@ void G_QueueBuildPoints( gentity_t *self )
queueFraction = 1.0;
queuePoints = (int) ( queueFraction * (double) BG_Buildable( self->s.modelindex )->buildPoints );
+ return queuePoints;
+}
+
+/*
+============
+G_QueueBuildPoints
+============
+*/
+void G_QueueBuildPoints( gentity_t *self )
+{
+ gentity_t *powerEntity;
+ int queuePoints;
+
+ queuePoints = G_QueueValue( self );
if( !queuePoints )
return;
@@ -3423,6 +3437,12 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
vec3_t normal;
char readable[ MAX_STRING_CHARS ];
char buildnums[ MAX_STRING_CHARS ];
+ buildLog_t *log;
+
+ if( builder->client )
+ log = G_BuildLogNew( builder, BF_CONSTRUCT );
+ else
+ log = NULL;
// Free existing buildables
G_FreeMarkedBuildables( builder, readable, sizeof( readable ),
@@ -3654,6 +3674,9 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable, vec3_t ori
readable );
}
+ if( log )
+ G_BuildLogSet( log, built );
+
return built;
}
@@ -3742,7 +3765,7 @@ Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
-static void G_FinishSpawningBuildable( gentity_t *ent )
+static gentity_t *G_FinishSpawningBuildable( gentity_t *ent, qboolean force )
{
trace_t tr;
vec3_t dest;
@@ -3750,7 +3773,6 @@ static void G_FinishSpawningBuildable( gentity_t *ent )
buildable_t buildable = ent->s.modelindex;
built = G_Build( ent, buildable, ent->s.pos.trBase, ent->s.angles );
- G_FreeEntity( ent );
built->takedamage = qtrue;
built->spawned = qtrue; //map entities are already spawned
@@ -3763,12 +3785,12 @@ static void G_FinishSpawningBuildable( gentity_t *ent )
trap_Trace( &tr, built->s.origin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask );
- if( tr.startsolid )
+ if( tr.startsolid && !force )
{
G_Printf( S_COLOR_YELLOW "G_FinishSpawningBuildable: %s startsolid at %s\n",
built->classname, vtos( built->s.origin ) );
G_FreeEntity( built );
- return;
+ return NULL;
}
//point items in the correct direction
@@ -3780,6 +3802,20 @@ static void G_FinishSpawningBuildable( gentity_t *ent )
G_SetOrigin( built, tr.endpos );
trap_LinkEntity( built );
+ return built;
+}
+
+/*
+============
+G_SpawnBuildableThink
+
+Complete spawning a buildable using it's placeholder
+============
+*/
+static void G_SpawnBuildableThink( gentity_t *ent )
+{
+ G_FinishSpawningBuildable( ent, qfalse );
+ G_FreeEntity( ent );
}
/*
@@ -3799,7 +3835,7 @@ void G_SpawnBuildable( gentity_t *ent, buildable_t buildable )
// some movers spawn on the second frame, so delay item
// spawns until the third frame so they can ride trains
ent->nextthink = level.time + FRAMETIME * 2;
- ent->think = G_FinishSpawningBuildable;
+ ent->think = G_SpawnBuildableThink;
}
/*
@@ -4103,3 +4139,174 @@ void G_BaseSelfDestruct( team_t team )
}
}
+/*
+============
+build log
+============
+*/
+buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate )
+{
+ buildLog_t *log = &level.buildLog[ level.buildId++ % MAX_BUILDLOG ];
+
+ if( level.numBuildLogs < MAX_BUILDLOG )
+ level.numBuildLogs++;
+ log->time = level.time;
+ log->fate = fate;
+ log->actor = actor && actor->client ? actor->client->pers.namelog : NULL;
+ return log;
+}
+
+void G_BuildLogSet( buildLog_t *log, gentity_t *ent )
+{
+ log->modelindex = ent->s.modelindex;
+ log->deconstruct = log->deconstruct;
+ log->deconstructTime = ent->deconstructTime;
+ VectorCopy( ent->s.pos.trBase, log->origin );
+ VectorCopy( ent->s.angles, log->angles );
+ VectorCopy( ent->s.origin2, log->origin2 );
+ VectorCopy( ent->s.angles2, log->angles2 );
+ log->powerSource = ent->parentNode ? ent->parentNode->s.modelindex : BA_NONE;
+ log->powerValue = G_QueueValue( ent );
+}
+
+void G_BuildLogAuto( gentity_t *actor, gentity_t *buildable, buildFate_t fate )
+{
+ G_BuildLogSet( G_BuildLogNew( actor, fate ), buildable );
+}
+
+void G_BuildLogRevertThink( gentity_t *ent )
+{
+ gentity_t *built;
+ vec3_t mins, maxs;
+ int blockers[ MAX_GENTITIES ];
+ int num;
+ int victims = 0;
+ int i;
+
+ if( ent->suicideTime > level.time )
+ {
+ BG_BuildableBoundingBox( ent->s.modelindex, mins, maxs );
+ VectorAdd( ent->s.pos.trBase, mins, mins );
+ VectorAdd( ent->s.pos.trBase, maxs, maxs );
+ num = trap_EntitiesInBox( mins, maxs, blockers, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ gentity_t *targ;
+ vec3_t push;
+
+ targ = g_entities + blockers[ i ];
+ if( targ->client )
+ {
+ float val = ( targ->client->ps.eFlags & EF_WALLCLIMB) ? 300.0 : 150.0;
+
+ VectorSet( push, crandom() * val, crandom() * val, random() * val );
+ VectorAdd( targ->client->ps.velocity, push, targ->client->ps.velocity );
+ victims++;
+ }
+ }
+
+ if( victims )
+ {
+ // still a blocker
+ ent->nextthink = level.time + FRAMETIME;
+ return;
+ }
+ }
+
+ built = G_FinishSpawningBuildable( ent, qtrue );
+ if( ( built->deconstruct = ent->deconstruct ) )
+ built->deconstructTime = ent->deconstructTime;
+ built->buildTime = built->s.time = 0;
+ G_KillBox( built );
+
+ G_LogPrintf( "revert: restore %d %s\n",
+ built - g_entities, BG_Buildable( built->s.modelindex )->name );
+
+ G_FreeEntity( ent );
+}
+
+void G_BuildLogRevert( int id )
+{
+ buildLog_t *log;
+ gentity_t *ent;
+ int i;
+ vec3_t dist;
+
+ level.numBuildablesForRemoval = 0;
+
+ level.numBuildLogs -= level.buildId - id;
+ while( level.buildId > id )
+ {
+ log = &level.buildLog[ --level.buildId % MAX_BUILDLOG ];
+ if( log->fate == BF_CONSTRUCT )
+ {
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ ent = &g_entities[ i ];
+ if( ent->s.eType != ET_BUILDABLE ||
+ ent->s.modelindex != log->modelindex ||
+ ent->health <= 0 )
+ continue;
+
+ VectorSubtract( ent->s.pos.trBase, log->origin, dist );
+ if( VectorLengthSquared( dist ) > 2.0f )
+ continue;
+
+ G_LogPrintf( "revert: remove %d %s\n",
+ ent - g_entities, BG_Buildable( ent->s.modelindex )->name );
+ G_FreeEntity( ent );
+ break;
+ }
+ }
+ else
+ {
+ gentity_t *builder = G_Spawn();
+
+ builder->client = NULL;
+ VectorCopy( log->origin, builder->s.pos.trBase );
+ VectorCopy( log->angles, builder->s.angles );
+ VectorCopy( log->origin2, builder->s.origin2 );
+ VectorCopy( log->angles2, builder->s.angles2 );
+ builder->s.modelindex = log->modelindex;
+ builder->deconstruct = log->deconstruct;
+ builder->deconstructTime = log->deconstructTime;
+
+ builder->think = G_BuildLogRevertThink;
+ builder->nextthink = level.time + FRAMETIME;
+ builder->suicideTime = level.time + 3000;
+
+ if( log->fate == BF_DESTROY )
+ {
+ int value = log->powerValue;
+
+ if( BG_Buildable( log->modelindex )->team == TEAM_ALIENS )
+ {
+ level.alienBuildPointQueue =
+ MAX( 0, level.alienBuildPointQueue - value );
+ }
+ else
+ {
+ if( log->powerSource == BA_H_REACTOR )
+ {
+ level.humanBuildPointQueue =
+ MAX( 0, level.humanBuildPointQueue - value );
+ }
+ else if( log->powerSource == BA_H_REPEATER )
+ {
+ gentity_t *source;
+ buildPointZone_t *zone;
+
+ source = G_PowerEntityForPoint( log->origin );
+ if( source && source->usesBuildPointZone )
+ {
+ zone = &level.buildPointZones[ source->buildPointZone ];
+ zone->queuedBuildPoints =
+ MAX( 0, zone->queuedBuildPoints - value );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+