summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorenneract <trem.redman@gmail.com>2014-02-25 13:03:43 +0100
committerenneract <trem.redman@gmail.com>2014-02-25 13:03:43 +0100
commitdac3d3127fc94231bdde0c0822bb12de01e9e836 (patch)
tree17829bc1a1b0ddb2d49421c5ea0114b4c2eff436 /src
parentcd9f8731a13a29d51a401f67ec2aa0b8962e01c8 (diff)
0.1.7
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_buildable.c682
-rw-r--r--src/cgame/cg_draw.c81
-rw-r--r--src/cgame/cg_ents.c3
-rw-r--r--src/cgame/cg_event.c19
-rw-r--r--src/cgame/cg_local.h121
-rw-r--r--src/cgame/cg_main.c92
-rw-r--r--src/cgame/cg_playerstate.c6
-rw-r--r--src/cgame/cg_servercmds.c11
-rw-r--r--src/cgame/cg_tutorial.c48
-rw-r--r--src/cgame/cg_weapons.c292
-rw-r--r--src/game/bg_misc.c244
-rw-r--r--src/game/bg_public.h41
-rw-r--r--src/game/g_active.c123
-rw-r--r--src/game/g_buildable.c2285
-rw-r--r--src/game/g_client.c8
-rw-r--r--src/game/g_cmds.c108
-rw-r--r--src/game/g_combat.c26
-rw-r--r--src/game/g_local.h64
-rw-r--r--src/game/g_main.c141
-rw-r--r--src/game/g_weapon.c4
-rw-r--r--src/game/tremulous.h89
-rw-r--r--src/ui/ui_main.c35
22 files changed, 2525 insertions, 1998 deletions
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index 0c851b0..5646f90 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -45,6 +45,77 @@ char *cg_buildableSoundNames[ MAX_BUILDABLE_ANIMATIONS ] =
static sfxHandle_t defaultAlienSounds[ MAX_BUILDABLE_ANIMATIONS ];
static sfxHandle_t defaultHumanSounds[ MAX_BUILDABLE_ANIMATIONS ];
+/*
+======================
+CG_RenderCuboid
+
+Render a cuboid with proper lighting and UV maps
+======================
+*/
+static void CG_RenderCuboid_Face( vec3_t a, vec3_t b, vec3_t c, vec3_t d,
+ int da, int db,
+ vec4_t color,
+ float texscale, qhandle_t shader )
+{
+ polyVert_t verts[ 4 ];
+
+ VectorCopy( d, verts[ 0 ].xyz );
+ verts[ 0 ].st[ 0 ] = d[ da ] * texscale;
+ verts[ 0 ].st[ 1 ] = d[ db ] * texscale;
+ Vector4Copy( color, verts[ 0 ].modulate );
+ VectorCopy( c, verts[ 1 ].xyz );
+ verts[ 1 ].st[ 0 ] = c[ da ] * texscale;
+ verts[ 1 ].st[ 1 ] = c[ db ] * texscale;
+ Vector4Copy( color, verts[ 1 ].modulate );
+ VectorCopy( b, verts[ 2 ].xyz );
+ verts[ 2 ].st[ 0 ] = b[ da ] * texscale;
+ verts[ 2 ].st[ 1 ] = b[ db ] * texscale;
+ Vector4Copy( color, verts[ 2 ].modulate );
+ VectorCopy( a, verts[ 3 ].xyz );
+ verts[ 3 ].st[ 0 ] = a[ da ] * texscale;
+ verts[ 3 ].st[ 1 ] = a[ db ] * texscale;
+ Vector4Copy( color, verts[ 3 ].modulate );
+
+ trap_R_AddPolyToScene( shader, 4, verts );
+}
+
+static void CG_RenderCuboid( vec3_t mins, vec3_t maxs, float texscale, qhandle_t shader )
+{
+ int i;
+ vec3_t midpoint, ambient, directed, idc;
+ vec4_t color = { 255.0f, 255.0f, 255.0f, 255.0f };
+ vec3_t ppp, ppn, pnp, pnn, npp, npn, nnp, nnn;
+
+ //lighting
+ VectorAdd( mins, maxs, midpoint );
+ VectorScale( midpoint, 0.5f, midpoint );
+ trap_R_LightForPoint( midpoint, ambient, directed, idc );
+ VectorAdd( ambient, directed, color );
+ for( i = 0; i < 3; i++ )
+ if( color[ i ] > 255.0f )
+ color[ i ] = 255.0f;
+
+ //vertices
+ VectorSet( ppp, maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( ppn, maxs[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( pnp, maxs[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( pnn, maxs[ 0 ], mins[ 1 ], mins[ 2 ] );
+ VectorSet( npp, mins[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+ VectorSet( npn, mins[ 0 ], maxs[ 1 ], mins[ 2 ] );
+ VectorSet( nnp, mins[ 0 ], mins[ 1 ], maxs[ 2 ] );
+ VectorSet( nnn, mins[ 0 ], mins[ 1 ], mins[ 2 ] );
+
+ //faces
+ //+-x
+ CG_RenderCuboid_Face( ppn, ppp, pnp, pnn, 1, 2, color, texscale, shader );
+ CG_RenderCuboid_Face( nnn, nnp, npp, npn, 1, 2, color, texscale, shader );
+ //+-y
+ CG_RenderCuboid_Face( ppp, ppn, npn, npp, 0, 2, color, texscale, shader );
+ CG_RenderCuboid_Face( nnp, nnn, pnn, pnp, 0, 2, color, texscale, shader );
+ //+-z
+ CG_RenderCuboid_Face( npp, nnp, pnp, ppp, 0, 1, color, texscale, shader );
+ CG_RenderCuboid_Face( ppn, pnn, nnn, npn, 0, 1, color, texscale, shader );
+}
/*
======================
@@ -1283,7 +1354,6 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
int health;
float x, y;
vec4_t color;
- qboolean powered, marked;
trace_t tr;
float d;
buildStat_t *bs;
@@ -1378,8 +1448,8 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
}
}
- if(cuboid)
- visible=qtrue;
+ if( cuboid )
+ visible = qtrue;
// hack to make the kit obscure view
if( cg_drawGun.integer && visible &&
@@ -1429,13 +1499,13 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
else if( healthScale > 1.0f )
healthScale = 1.0f;
- if(cuboid)
+ if( cuboid )
{
- x=320;
- y=240;
- d=Distance(cg.refdef.vieworg,trac);
- if(d<64.0f)
- d=64.0f;
+ x = 320;
+ y = 240;
+ d = Distance( cg.refdef.vieworg, trac );
+ if( d < 64.0f )
+ d = 64.0f ;
}
else
if( !CG_WorldToScreen( origin, &x, &y ) )
@@ -1454,9 +1524,6 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
// this is fudged to get the width/height in the cfg to be more realistic
scale = ( picH / d ) * 3;
- powered = es->eFlags & EF_B_POWERED;
- marked = es->eFlags & EF_B_MARKED;
-
picH *= scale;
picW *= scale;
picX -= ( picW * 0.5f );
@@ -1527,20 +1594,21 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
}
trap_R_SetColor( color );
- if( !powered )
+
{
float pX;
-
+
pX = picX + ( subH * bs->horizontalMargin );
- CG_DrawPic( pX, subY, subH, subH, bs->noPowerShader );
- }
-
- if( marked )
- {
- float mX;
-
- mX = picX + picW - ( subH * bs->horizontalMargin ) - subH;
- CG_DrawPic( mX, subY, subH, subH, bs->markedShader );
+
+ if( BG_Buildable( es->modelindex, NULL )->team == TEAM_HUMANS )
+ {
+ float offs = 2000.0f / d;
+ CG_DrawPic( pX - offs, subY - offs,
+ subH + 2.0f * offs, subH + 2.0f * offs,
+ CG_BuildablePowerStatusIcon( es ) );
+ }
+ else if( !( es->eFlags & EF_B_POWERED ) )
+ CG_DrawPic( pX, subY, subH, subH, bs->noPowerShader );
}
//NOTE: dont use CG_DrawField, too few digits
@@ -1555,19 +1623,22 @@ static void CG_BuildableStatusDisplay( centity_t *cent, qboolean cuboid, vec3_t
if( health > 0 && healthPoints < 1 )
healthPoints = 1;
- Com_sprintf(buf,sizeof(buf),"%i",healthPoints);
- bufl=strlen(buf);
- cW=subH*cgDC.aspectScale;
- cH=subH;
- nX=picX+picW*0.5f-cW*bufl*0.5f;
+ Com_sprintf( buf, sizeof( buf ), "%i", healthPoints );
+ bufl = strlen(buf);
+ cW = subH*cgDC.aspectScale;
+ cH = subH;
+ nX = picX + picW * 0.5f - cW * bufl * 0.5f;
- for(i=0;i<bufl;i++)
+ for( i = 0; i < bufl; i++ )
{
- if(buf[i]=='-')
- frame=STAT_MINUS;
- else
- frame=buf[i]-'0';
- CG_DrawPic(nX+i*cW,y+bs->verticalMargin-subH*0.5f,cW,cH,cgs.media.numberShaders[frame]);
+ if( buf[ i ] == '-' )
+ frame = STAT_MINUS;
+ else
+ frame = buf[ i ] - '0';
+ CG_DrawPic( nX + i * cW,
+ y + bs->verticalMargin - subH * 0.5f,
+ cW, cH,
+ cgs.media.numberShaders[ frame ] );
}
}
@@ -1620,28 +1691,6 @@ static qboolean CG_PlayerIsBuilder( buildable_t buildable )
/*
==================
-CG_BuildableRemovalPending
-==================
-*/
-static qboolean CG_BuildableRemovalPending( int entityNum )
-{
- int i;
- playerState_t *ps = &cg.snap->ps;
-
- if( !( ps->stats[ STAT_BUILDABLE ] & SB_VALID_TOGGLEBIT ) )
- return qfalse;
-
- for( i = 0; i < MAX_MISC; i++ )
- {
- if( ps->misc[ i ] == entityNum )
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-==================
CG_DrawBuildableStatus
==================
*/
@@ -1656,7 +1705,7 @@ void CG_DrawBuildableStatus( void )
trace_t tr;
qboolean cuboid;
- if((cg.predictedPlayerState.stats[STAT_BUILDABLE]&~SB_VALID_TOGGLEBIT)>BA_NONE)
+ if( ( cg.predictedPlayerState.stats[STAT_BUILDABLE] & ~SB_VALID_TOGGLEBIT) > BA_NONE )
return; //hide buildstats if we're placing a buildable
for( i = 0; i < cg.snap->numEntities; i++ )
@@ -1674,8 +1723,8 @@ void CG_DrawBuildableStatus( void )
qsort( buildableList, buildables, sizeof( int ), CG_SortDistance );
for( i = 0; i < buildables; i++ )
{
- cuboid = BG_Buildable(cg_entities[buildableList[i]].currentState.modelindex,NULL)->cuboid;
- if(cuboid && tr.entityNum!=buildableList[i] )
+ cuboid = BG_IsCuboid( cg_entities[ buildableList[ i ] ].currentState.modelindex );
+ if(cuboid && tr.entityNum != buildableList[ i ] )
continue;
CG_BuildableStatusDisplay( &cg_entities[ buildableList[ i ] ], cuboid, tr.endpos );
}
@@ -1713,11 +1762,11 @@ void CG_Buildable( centity_t *cent )
return;
}
- // cuboids use a bit different rendering code !@#CUBOID
+ // cuboids use a bit different rendering code
if( BG_IsCuboid( es->modelindex ) )
{
- qhandle_t texture=0,cracks=0;
- vec3_t dims;
+ qhandle_t texture = 0,cracks = 0;
+ vec3_t dims, mins, maxs;
const cuboidAttributes_t *cuboidAttr;
const cuboidInfo_t *cuboidInfo;
int i, health, sound;
@@ -1733,12 +1782,30 @@ void CG_Buildable( centity_t *cent )
else if ( healthPct < 0.0f )
healthPct = 0.0f;
- if( cuboidInfo->useCracks )
+ if( ( es->eFlags & EF_B_SPAWNED ) && cuboidInfo->useCracks && healthPct < 0.95f )
{
+ float progress;
+ const float o = 1.02f; //md3 rendering is not exact, so render it bigger to compensate
+
if( cuboidInfo->textureCount )
texture = cuboidInfo->textures[ 0 ];
- if( healthPct < 0.75f )
- cracks = cgs.media.cuboidCracks[ (int)( CUBOID_CRACK_TEXTURES - 1 - floor( CUBOID_CRACK_TEXTURES * healthPct ) ) - 1 ];
+
+ memset( &ent, 0, sizeof( ent ) );
+ ent.reType = RT_MODEL;
+ VectorCopy( cent->lerpOrigin, ent.origin );
+
+ ent.axis[0][0]=-dims[0]/2.0f*o;ent.axis[0][1]=0.0f; ent.axis[0][2]=0.0f;
+ ent.axis[1][0]=0.0f; ent.axis[1][1]=-dims[1]/2.0f*o;ent.axis[1][2]=0.0f;
+ ent.axis[2][0]=0.0f; ent.axis[2][1]=0.0f; ent.axis[2][2]=dims[2]/2.0f*o;
+ ent.nonNormalizedAxes = qtrue;
+
+ progress = healthPct;
+
+ ent.customShader = cgs.media.cuboidCracks;
+ ent.shaderTime = 0.001f * cg.time + progress;
+
+ ent.hModel = cgs.media.cuboidModel;
+ trap_R_AddRefEntityToScene( &ent );
}
else
for( i = 0; i < cuboidInfo->textureCount; i++ )
@@ -1750,13 +1817,22 @@ void CG_Buildable( centity_t *cent )
if( !( es->eFlags & EF_B_SPAWNED ) )
{
- sfxHandle_t prebuildSound=cgs.media.humanBuildablePrebuild;
+ sfxHandle_t prebuildSound;
+
if( team == TEAM_HUMANS )
{
- texture = cgs.media.humanSpawningShader;
- prebuildSound = cgs.media.humanBuildablePrebuild;
+ if( es->eFlags & EF_B_POWERED )
+ {
+ texture = cgs.media.humanSpawningShader;
+ prebuildSound = cgs.media.humanBuildablePrebuild;
+ }
+ else
+ {
+ texture = cgs.media.humanUnpoweredSpawningShader;
+ prebuildSound = cgs.media.unpoweredSurgeLoop;
+ }
}
- else if(team==TEAM_ALIENS)
+ else if( team == TEAM_ALIENS )
{
texture = cgs.media.cuboidAlienPrebuild;
prebuildSound = cgs.media.alienBuildablePrebuild;
@@ -1764,24 +1840,11 @@ void CG_Buildable( centity_t *cent )
cracks = 0;
trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
}
-
- memset( &ent, 0, sizeof( ent ) );
- ent.reType = RT_MODEL;
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( cent->lerpOrigin, ent.oldorigin );
- VectorCopy( cent->lerpOrigin, ent.lightingOrigin );
-
- //NOTE: don't use CG_PositionAndOrientateBuildable, it screws up everything
- ent.axis[0][0]=-dims[0]/2.0f;ent.axis[0][1]=0.0f; ent.axis[0][2]=0.0f;
- ent.axis[1][0]=0.0f; ent.axis[1][1]=-dims[1]/2.0f;ent.axis[1][2]=0.0f;
- ent.axis[2][0]=0.0f; ent.axis[2][1]=0.0f; ent.axis[2][2]=dims[2]/2.0f;
- ent.nonNormalizedAxes = qtrue;
-
- ent.customShader = texture;
- ent.hModel = cgs.media.cuboidModel;
- trap_R_AddRefEntityToScene( &ent );
- if( cracks )
- CG_DrawCuboid( ent.origin, dims, cracks, 1 );
+
+ BG_CuboidBBox( dims, mins, maxs );
+ VectorAdd( mins, cent->lerpOrigin, mins );
+ VectorAdd( maxs, cent->lerpOrigin, maxs );
+ CG_RenderCuboid( mins, maxs, 0.01f, texture );
if( health < cent->lastBuildableHealth && ( es->eFlags & EF_B_SPAWNED ) )
{
@@ -1795,247 +1858,253 @@ void CG_Buildable( centity_t *cent )
}
}
else
- {
-
- memset ( &ent, 0, sizeof( ent ) );
+ {
+ memset ( &ent, 0, sizeof( ent ) );
- VectorCopy( cent->lerpOrigin, ent.origin );
- VectorCopy( cent->lerpOrigin, ent.oldorigin );
- VectorCopy( cent->lerpOrigin, ent.lightingOrigin );
+ VectorCopy( cent->lerpOrigin, ent.origin );
+ VectorCopy( cent->lerpOrigin, ent.oldorigin );
+ VectorCopy( cent->lerpOrigin, ent.lightingOrigin );
- VectorCopy( es->origin2, surfNormal );
+ VectorCopy( es->origin2, surfNormal );
- VectorCopy( es->angles, angles );
- BG_BuildableBoundingBox( es->modelindex, mins, maxs );
+ VectorCopy( es->angles, angles );
+ BG_BuildableBoundingBox( es->modelindex, mins, maxs );
- if( es->pos.trType == TR_STATIONARY )
- {
- // Positioning a buildable involves potentially up to two traces, and
- // seeing as buildables rarely move, we cache the results and recalculate
- // only if the buildable moves or changes orientation
- if( VectorCompare( cent->buildableCache.cachedOrigin, cent->lerpOrigin ) &&
- VectorCompare( cent->buildableCache.cachedNormal, surfNormal ) )
- {
- VectorCopy( cent->buildableCache.axis[ 0 ], ent.axis[ 0 ] );
- VectorCopy( cent->buildableCache.axis[ 1 ], ent.axis[ 1 ] );
- VectorCopy( cent->buildableCache.axis[ 2 ], ent.axis[ 2 ] );
- VectorCopy( cent->buildableCache.origin, ent.origin );
- }
- else
+ if( es->pos.trType == TR_STATIONARY )
{
- CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal,
- es->number, mins, maxs, ent.axis,
- ent.origin, qfalse );
- VectorCopy( ent.axis[ 0 ], cent->buildableCache.axis[ 0 ] );
- VectorCopy( ent.axis[ 1 ], cent->buildableCache.axis[ 1 ] );
- VectorCopy( ent.axis[ 2 ], cent->buildableCache.axis[ 2 ] );
- VectorCopy( ent.origin, cent->buildableCache.origin );
- VectorCopy( cent->lerpOrigin, cent->buildableCache.cachedOrigin );
- VectorCopy( surfNormal, cent->buildableCache.cachedNormal );
+ // Positioning a buildable involves potentially up to two traces, and
+ // seeing as buildables rarely move, we cache the results and recalculate
+ // only if the buildable moves or changes orientation
+ if( VectorCompare( cent->buildableCache.cachedOrigin, cent->lerpOrigin ) &&
+ VectorCompare( cent->buildableCache.cachedNormal, surfNormal ) )
+ {
+ VectorCopy( cent->buildableCache.axis[ 0 ], ent.axis[ 0 ] );
+ VectorCopy( cent->buildableCache.axis[ 1 ], ent.axis[ 1 ] );
+ VectorCopy( cent->buildableCache.axis[ 2 ], ent.axis[ 2 ] );
+ VectorCopy( cent->buildableCache.origin, ent.origin );
+ }
+ else
+ {
+ CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal,
+ es->number, mins, maxs, ent.axis,
+ ent.origin, qfalse );
+ VectorCopy( ent.axis[ 0 ], cent->buildableCache.axis[ 0 ] );
+ VectorCopy( ent.axis[ 1 ], cent->buildableCache.axis[ 1 ] );
+ VectorCopy( ent.axis[ 2 ], cent->buildableCache.axis[ 2 ] );
+ VectorCopy( ent.origin, cent->buildableCache.origin );
+ VectorCopy( cent->lerpOrigin, cent->buildableCache.cachedOrigin );
+ VectorCopy( surfNormal, cent->buildableCache.cachedNormal );
+ }
}
- }
-
- VectorMA( ent.origin, BG_BuildableConfig( es->modelindex )->zOffset, surfNormal, ent.origin );
-
- VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
- VectorCopy( ent.origin, ent.lightingOrigin );
+ VectorMA( ent.origin, BG_BuildableConfig( es->modelindex )->zOffset, surfNormal, ent.origin );
+
- ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ];
+ VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all
+ VectorCopy( ent.origin, ent.lightingOrigin );
- if( !( es->eFlags & EF_B_SPAWNED ) )
- {
- sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild;
+ ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ];
- if( team == TEAM_HUMANS )
+ if( !( es->eFlags & EF_B_SPAWNED ) )
{
- ent.customShader = cgs.media.humanSpawningShader;
- prebuildSound = cgs.media.humanBuildablePrebuild;
- }
- else if( team == TEAM_ALIENS )
- prebuildSound = cgs.media.alienBuildablePrebuild;
+ sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild;
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
- }
+ if( team == TEAM_HUMANS )
+ {
+ if( es->eFlags & EF_B_POWERED )
+ {
+ ent.customShader = cgs.media.humanSpawningShader;
+ prebuildSound = cgs.media.humanBuildablePrebuild;
+ }
+ else
+ {
+ ent.customShader = cgs.media.humanUnpoweredSpawningShader;
+ prebuildSound = cgs.media.unpoweredSurgeLoop;
+ }
+ }
+ else if( team == TEAM_ALIENS )
+ prebuildSound = cgs.media.alienBuildablePrebuild;
+
+ trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound );
+ }
- CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
+ CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp );
- //rescale the model
- scale = BG_BuildableConfig( es->modelindex )->modelScale;
+ //rescale the model
+ scale = BG_BuildableConfig( es->modelindex )->modelScale;
- if( scale != 1.0f )
- {
- VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] );
- VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] );
- VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] );
+ if( scale != 1.0f )
+ {
+ VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] );
+ VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] );
+ VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] );
- ent.nonNormalizedAxes = qtrue;
- }
- else
- ent.nonNormalizedAxes = qfalse;
-
+ ent.nonNormalizedAxes = qtrue;
+ }
+ else
+ ent.nonNormalizedAxes = qfalse;
- if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
- ent.customShader = cgs.media.redBuildShader;
+ //add to refresh list
+ trap_R_AddRefEntityToScene( &ent );
- //add to refresh list
- trap_R_AddRefEntityToScene( &ent );
+ CrossProduct( surfNormal, refNormal, xNormal );
+ VectorNormalize( xNormal );
+ rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) );
- CrossProduct( surfNormal, refNormal, xNormal );
- VectorNormalize( xNormal );
- rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) );
+ //turret barrel bit
+ if( cg_buildables[ es->modelindex ].models[ 1 ] )
+ {
+ refEntity_t turretBarrel;
+ vec3_t flatAxis[ 3 ];
- //turret barrel bit
- if( cg_buildables[ es->modelindex ].models[ 1 ] )
- {
- refEntity_t turretBarrel;
- vec3_t flatAxis[ 3 ];
+ memset( &turretBarrel, 0, sizeof( turretBarrel ) );
- memset( &turretBarrel, 0, sizeof( turretBarrel ) );
+ turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ];
- turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ];
+ CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" );
+ VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin );
- CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" );
- VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin );
+ {
+ vec3_t interpolated;
+ int i;
- {
- vec3_t interpolated;
- int i;
+ for( i = 0; i < 3 ; i++ )
+ interpolated[ i ] = LerpAngle( es->angles2[ i ], cent->nextState.angles2[ i ], cg.frameInterpolation );
- for( i = 0; i < 3 ; i++ )
- interpolated[ i ] = LerpAngle( es->angles2[ i ], cent->nextState.angles2[ i ], cg.frameInterpolation );
+ AnglesToAxis( interpolated, flatAxis );
+ }
- AnglesToAxis( interpolated, flatAxis );
- }
+ RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
+ RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
+ RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
- RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
- RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
- RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
+ turretBarrel.oldframe = ent.oldframe;
+ turretBarrel.frame = ent.frame;
+ turretBarrel.backlerp = ent.backlerp;
- turretBarrel.oldframe = ent.oldframe;
- turretBarrel.frame = ent.frame;
- turretBarrel.backlerp = ent.backlerp;
+ turretBarrel.customShader = ent.customShader;
- turretBarrel.customShader = ent.customShader;
+ if( scale != 1.0f )
+ {
+ VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] );
+ VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] );
+ VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] );
- if( scale != 1.0f )
- {
- VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] );
- VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] );
- VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] );
+ turretBarrel.nonNormalizedAxes = qtrue;
+ }
+ else
+ turretBarrel.nonNormalizedAxes = qfalse;
- turretBarrel.nonNormalizedAxes = qtrue;
+ trap_R_AddRefEntityToScene( &turretBarrel );
}
- else
- turretBarrel.nonNormalizedAxes = qfalse;
-
- if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
- turretBarrel.customShader = cgs.media.redBuildShader;
- trap_R_AddRefEntityToScene( &turretBarrel );
- }
+ //turret barrel bit
+ if( cg_buildables[ es->modelindex ].models[ 2 ] )
+ {
+ refEntity_t turretTop;
+ vec3_t flatAxis[ 3 ];
+ vec3_t swivelAngles;
- //turret barrel bit
- if( cg_buildables[ es->modelindex ].models[ 2 ] )
- {
- refEntity_t turretTop;
- vec3_t flatAxis[ 3 ];
- vec3_t swivelAngles;
+ memset( &turretTop, 0, sizeof( turretTop ) );
- memset( &turretTop, 0, sizeof( turretTop ) );
+ VectorCopy( es->angles2, swivelAngles );
+ swivelAngles[ PITCH ] = 0.0f;
- VectorCopy( es->angles2, swivelAngles );
- swivelAngles[ PITCH ] = 0.0f;
+ turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ];
- turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ];
+ CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" );
+ VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin );
+ AnglesToAxis( swivelAngles, flatAxis );
- CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" );
- VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin );
- AnglesToAxis( swivelAngles, flatAxis );
+ RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
+ RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
+ RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
- RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle );
- RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle );
- RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle );
+ turretTop.oldframe = ent.oldframe;
+ turretTop.frame = ent.frame;
+ turretTop.backlerp = ent.backlerp;
- turretTop.oldframe = ent.oldframe;
- turretTop.frame = ent.frame;
- turretTop.backlerp = ent.backlerp;
+ turretTop.customShader = ent.customShader;
- turretTop.customShader = ent.customShader;
+ if( scale != 1.0f )
+ {
+ VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] );
+ VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] );
+ VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] );
- if( scale != 1.0f )
- {
- VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] );
- VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] );
- VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] );
+ turretTop.nonNormalizedAxes = qtrue;
+ }
+ else
+ turretTop.nonNormalizedAxes = qfalse;
- turretTop.nonNormalizedAxes = qtrue;
+ trap_R_AddRefEntityToScene( &turretTop );
}
- else
- turretTop.nonNormalizedAxes = qfalse;
-
- if( CG_PlayerIsBuilder( es->modelindex ) && CG_BuildableRemovalPending( es->number ) )
- turretTop.customShader = cgs.media.redBuildShader;
- trap_R_AddRefEntityToScene( &turretTop );
- }
-
- //weapon effects for turrets
- if( es->eFlags & EF_FIRING )
- {
- weaponInfo_t *weapon = &cg_weapons[ es->weapon ];
-
- if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ||
- BG_Buildable( es->modelindex, NULL )->turretProjType == WP_TESLAGEN )
+ //weapon effects for turrets
+ if( es->eFlags & EF_FIRING )
{
- if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] ||
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] ||
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] )
+ weaponInfo_t *weapon = &cg_weapons[ es->weapon ];
+
+ if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ||
+ BG_Buildable( es->modelindex, NULL )->turretProjType == WP_TESLAGEN )
{
- trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ),
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ],
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ],
- weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] );
+ if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] ||
+ weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] ||
+ weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] )
+ {
+ trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ),
+ weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ],
+ weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ],
+ weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] );
+ }
}
- }
- if( weapon->wim[ WPM_PRIMARY ].firingSound )
- {
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin,
- weapon->wim[ WPM_PRIMARY ].firingSound );
+ if( weapon->wim[ WPM_PRIMARY ].firingSound )
+ {
+ trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin,
+ weapon->wim[ WPM_PRIMARY ].firingSound );
+ }
+ else if( weapon->readySound )
+ trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound );
}
- else if( weapon->readySound )
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound );
- }
-
- //smoke etc for damaged buildables
- CG_BuildableParticleEffects( cent );
-
-
+
+ //smoke etc for damaged buildables
+ CG_BuildableParticleEffects( cent );
+
+
-
- health = es->generic1;
+
+ health = es->generic1;
- if( health < cent->lastBuildableHealth &&
- ( es->eFlags & EF_B_SPAWNED ) )
- {
- if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
+ if( health < cent->lastBuildableHealth &&
+ ( es->eFlags & EF_B_SPAWNED ) )
{
- if( team == TEAM_HUMANS )
+ if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
{
- int i = rand( ) % 4;
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
- }
- else if( team == TEAM_ALIENS )
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
+ if( team == TEAM_HUMANS )
+ {
+ int i = rand( ) % 4;
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
+ }
+ else if( team == TEAM_ALIENS )
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
- cent->lastBuildableDamageSoundTime = cg.time;
+ cent->lastBuildableDamageSoundTime = cg.time;
+ }
}
- }
-
- cent->lastBuildableHealth = health;
+ cent->lastBuildableHealth = health;
} //if (is a cuboid)
+
+
+ // play a loop if there's not enough power for it to build / activate
+ if( ( !( es->eFlags & EF_B_SPAWNED ) &&
+ !( es->eFlags & EF_B_POWERED ) ) ||
+ ( ( BG_Buildable( es->modelindex, NULL )->requiresPower ||
+ es->modelindex != BA_H_REPEATER ) &&
+ !( es->eFlags & EF_B_POWERED ) &&
+ ( es->eFlags & EF_B_SURGE ) ) )
+ trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, cgs.media.unpoweredSurgeLoop );
}
char cuboidInfo[128];
@@ -2049,17 +2118,21 @@ Draw the cuboid info string generated by CG_Cuboid_Info.
*/
void CG_Cuboid_DrawInfo(void)
{
- float x,y,w,h,s=0.5f;
+ float x,y,w,h,s=0.5f;
+
+ // disabled by default (replaced by ckit's display)
+ if( !cg_drawCuboidInfo.integer )
+ return;
- if(!BG_Buildable(cg.predictedPlayerState.stats[STAT_BUILDABLE]&~SB_VALID_TOGGLEBIT,NULL)->cuboid)
- return;
+ if( !BG_Buildable( cg.predictedPlayerState.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT, NULL )->cuboid )
+ return;
- w=UI_Text_Width(cuboidInfo,s);
- h=UI_Text_Height(cuboidInfo,s);
- x=320.0f-w/2.0f+cg_cuboidInfoX.value;
- y=240.0f-h/2.0f+cg_cuboidInfoY.value;
+ w= UI_Text_Width( cuboidInfo, s );
+ h= UI_Text_Height( cuboidInfo, s );
+ x= 320.0f - w / 2.0f + cg_cuboidInfoX.value;
+ y= 240.0f - h / 2.0f + cg_cuboidInfoY.value;
- UI_Text_Paint(x,y,s,colorWhite,cuboidInfo,0,0,ITEM_TEXTSTYLE_SHADOWEDMORE);
+ UI_Text_Paint( x, y, s, colorWhite, cuboidInfo, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
}
/*
@@ -2076,6 +2149,9 @@ void CG_Cuboid_Info(void)
const buildableAttributes_t *attr;
int axis=cg_cuboidResizeAxis.integer;
+ if( !cg_drawCuboidInfo.integer )
+ return;
+
attr=BG_Buildable(cg.predictedPlayerState.stats[STAT_BUILDABLE]&~SB_VALID_TOGGLEBIT,cg.cuboidSelection);
Com_sprintf(cuboidInfo,sizeof(cuboidInfo),
"^7[^3%c^7] | ^%c%.1f^7x^%c%.1f^7x^%c%.1f ^7| ^3%i^7HP | ^3%i^7ms | ^3%i^7BP",
@@ -2342,3 +2418,53 @@ void CG_CuboidAttack_f(void)
trap_SendClientCommand( va( "%s", CG_Argv(0) ) );
}
+/*
+======================
+CG_BuildablePowerStatusIcon
+
+Figures out the power status icon for a buildable
+======================
+*/
+qhandle_t CG_BuildablePowerStatusIcon( entityState_t *es )
+{
+ qboolean powered = ( es->eFlags & EF_B_POWERED );
+
+ if( !( es->eFlags & EF_B_SPAWNED ) )
+ {
+ if( powered )
+ return cgs.media.ckit_icon_surge;
+ else
+ return cgs.media.ckit_icon_nosurge;
+ }
+
+ if( BG_Buildable( es->modelindex, NULL )->isPowerSource ||
+ es->modelindex == BA_H_REPEATER )
+ {
+ qboolean active = ( es->eFlags & EF_B_SURGE );
+
+ if( !active )
+ return cgs.media.ckit_icon_off;
+ else if( powered )
+ return cgs.media.ckit_icon_power;
+ else
+ return cgs.media.ckit_icon_nopower;
+ }
+ else
+ {
+ if( !( es->eFlags & EF_B_SURGE ) )
+ {
+ if( powered )
+ return cgs.media.ckit_icon_power;
+ else
+ return cgs.media.ckit_icon_nopower;
+ }
+ else
+ {
+ if( powered )
+ return cgs.media.ckit_icon_surge;
+ else
+ return cgs.media.ckit_icon_nosurge;
+ }
+ }
+ return 0;
+}
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index aa6df3d..e9cccf4 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -636,7 +636,6 @@ static void CG_DrawPlayerWallclimbing( rectDef_t *rect, vec4_t backColor, vec4_t
static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
{
int value;
- int valueMarked = -1;
qboolean bp = qfalse;
switch( BG_PrimaryWeapon( cg.snap->ps.stats ) )
@@ -648,8 +647,7 @@ static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
case WP_ABUILD:
case WP_ABUILD2:
case WP_HBUILD:
- value = cg.snap->ps.persistant[ PERS_BP ];
- valueMarked = cg.snap->ps.persistant[ PERS_MARKEDBP ];
+ value = cg.snap->ps.persistant[ PERS_BUILDPOINTS ];
bp = qtrue;
break;
@@ -660,8 +658,6 @@ static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
if( value > 999 )
value = 999;
- if( valueMarked > 999 )
- valueMarked = 999;
if( value > -1 )
{
@@ -678,10 +674,7 @@ static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
return;
}
- if( valueMarked > 0 )
- text = va( "%d+(%d)", value, valueMarked );
- else
- text = va( "%d", value );
+ text = va( "%d", value );
len = strlen( text );
@@ -2557,10 +2550,10 @@ CG_DrawCrosshair
static void CG_DrawCrosshair( rectDef_t *rect, vec4_t color )
{
float w, h;
- qhandle_t hShader;
float x, y;
weaponInfo_t *wi;
weapon_t weapon;
+ qboolean hit, ff;
weapon = BG_GetPlayerWeapon( &cg.snap->ps );
@@ -2590,24 +2583,66 @@ static void CG_DrawCrosshair( rectDef_t *rect, vec4_t color )
x = rect->x + ( rect->w / 2 ) - ( w / 2 );
y = rect->y + ( rect->h / 2 ) - ( h / 2 );
- hShader = wi->crossHair;
+ hit = ( cg.time <= cg.lastHitTime + 75 );
+ ff = ( cg.time == cg.crosshairClientTime || cg.crosshairBuildable >= 0 );
- //aiming at a friendly player/buildable, dim the crosshair
- if( cg.time == cg.crosshairClientTime || cg.crosshairBuildable >= 0 )
- {
- int i;
- for( i = 0; i < 3; i++ )
- color[i] *= .5f;
+ color[ 3 ] = 0.6f;
- }
-
- if( hShader != 0 )
+ trap_R_SetColor( color );
+
+ switch( wi->crossHairType )
{
+ case CH_NONE:
+ break;
+
+ case CH_DOT:
+ if( ff )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_friendly );
+ else
+ CG_DrawPic( x, y, w, h, cgs.media.ch_dot );
- trap_R_SetColor( color );
- CG_DrawPic( x, y, w, h, hShader );
- trap_R_SetColor( NULL );
+ if( hit )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_dothit );
+
+ break;
+
+ case CH_CIRCLE:
+ if( ff )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_friendly );
+
+ if( hit )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_circlehit );
+ else
+ CG_DrawPic( x, y, w, h, cgs.media.ch_circle );
+
+ break;
+
+ case CH_CIRCLEDDOT:
+ if( ff )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_friendly );
+ else
+ CG_DrawPic( x, y, w, h, cgs.media.ch_dot );
+
+ if( hit )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_circlehit );
+ else
+ CG_DrawPic( x, y, w, h, cgs.media.ch_circle );
+
+ break;
+
+ case CH_ALIEN:
+ if( ff )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_afriendly );
+ else
+ CG_DrawPic( x, y, w, h, cgs.media.ch_adot );
+
+ if( hit )
+ CG_DrawPic( x, y, w, h, cgs.media.ch_acircle );
+
+ break;
}
+
+ trap_R_SetColor( NULL );
}
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 339cd8e..6b1523d 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -236,7 +236,8 @@ static void CG_EntityEffects( centity_t *cent )
// constant light glow
- if ( cent->currentState.constantLight )
+ if ( cent->currentState.constantLight &&
+ cent->currentState.eType != ET_BUILDABLE )
{
int cl;
int i, r, g, b;
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index c8ca2e6..adc319c 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -808,6 +808,25 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound );
break;
+ case EV_POWER_SWITCH:
+ trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.powerSwitchSound );
+ break;
+
+ case EV_POWER_ZAP:
+ {
+ particleSystem_t *ps;
+ ps = CG_SpawnNewParticleSystem( cgs.media.humanPowerZapPS );
+
+ if( CG_IsParticleSystemValid( &ps ) )
+ {
+ CG_SetAttachmentPoint( &ps->attachment, position );
+ CG_SetAttachmentCent( &ps->attachment, cg_entities + es->number );
+ CG_AttachToPoint( &ps->attachment );
+ }
+ }
+ trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.powerZap[ rand() % 4 ] );
+ break;
+
case EV_GRENADE_BOUNCE:
if( rand( ) & 1 )
trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound1 );
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index a81d1df..e4949b5 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -79,8 +79,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define TEAM_OVERLAY_MAXNAME_WIDTH 12
#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16
-#define CUBOID_CRACK_TEXTURES 4
-
typedef enum
{
FOOTSTEP_NORMAL,
@@ -814,6 +812,15 @@ typedef struct weaponInfoMode_s
sfxHandle_t impactFleshSound[ 4 ]; //random impact sound
} weaponInfoMode_t;
+enum
+{
+ CH_NONE,
+ CH_DOT,
+ CH_CIRCLE,
+ CH_CIRCLEDDOT,
+ CH_ALIEN
+};
+
// each WP_* weapon enum has an associated weaponInfo_t
// that contains media references necessary to present the
// weapon and its effects
@@ -839,7 +846,7 @@ typedef struct weaponInfo_s
qhandle_t weaponIcon;
qhandle_t ammoIcon;
- qhandle_t crossHair;
+ int crossHairType;
int crossHairSize;
sfxHandle_t readySound;
@@ -932,6 +939,25 @@ typedef struct
#define MAX_CONSOLE_TEXT 8192
#define MAX_CONSOLE_LINES 32
+#define MAX_CKIT_ROWS 6
+#define MAX_CKIT_COLUMNS 7
+#define MAX_CKIT_TEXT 64 //make it big so Com_sprintf won't spam errors
+
+typedef struct
+{
+ qhandle_t icon;
+ char text[ MAX_CKIT_TEXT ];
+} ckitDisplayLine_t;
+
+typedef struct
+{
+ qhandle_t background;
+ qhandle_t bigicona;
+ qhandle_t bigiconb;
+ ckitDisplayLine_t lines[ MAX_CKIT_ROWS ];
+} ckitDisplay_t;
+
+
// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action
// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after
@@ -1194,6 +1220,16 @@ typedef struct
qhandle_t announcerStack[ MAX_ANNOUNCER_STACK ];
int announcerStackPos;
int announcerStackLatest;
+
+ // no space for voltage and current information so they're being sent
+ // over the network in commands
+ int bse_entityNum;
+ float bse_voltage;
+ float bse_current;
+
+ ckitDisplay_t ckitDisp;
+
+ int lastHitTime;
} cg_t;
@@ -1228,6 +1264,7 @@ typedef struct
qhandle_t teamOverlayShader;
qhandle_t numberShaders[ 11 ];
+ qhandle_t digitalNumberShaders[ 12 ]; // note: 11 is comma
qhandle_t shadowMarkShader;
qhandle_t wakeMarkShader;
@@ -1236,6 +1273,7 @@ typedef struct
qhandle_t greenBuildShader;
qhandle_t redBuildShader;
qhandle_t humanSpawningShader;
+ qhandle_t humanUnpoweredSpawningShader;
// disconnect
qhandle_t disconnectPS;
@@ -1337,13 +1375,17 @@ typedef struct
qhandle_t humanBleedPS;
qhandle_t alienBuildableBleedPS;
qhandle_t humanBuildableBleedPS;
-
+
+ qhandle_t humanPowerZapPS;
qhandle_t teslaZapTS;
sfxHandle_t lCannonWarningSound;
sfxHandle_t lCannonWarningSound2;
+ qhandle_t friendlyCrosshair;
+ qhandle_t hitCrosshair;
+
qhandle_t buildWeaponTimerPie[ 8 ];
qhandle_t upgradeClassIconShader;
qhandle_t healthCross;
@@ -1353,7 +1395,7 @@ typedef struct
qhandle_t healthCrossPoisoned;
qhandle_t healthCrossImplanted;
- qhandle_t cuboidCracks[CUBOID_CRACK_TEXTURES-1];
+ qhandle_t cuboidCracks;
qhandle_t cuboidModel;
qhandle_t cuboidRedBuildShader;
qhandle_t cuboidYellowBuildShader;
@@ -1378,6 +1420,50 @@ typedef struct
qhandle_t basivisionShader;
qhandle_t basivisionBlipShader;
qhandle_t basivisionFlareShader;
+
+ sfxHandle_t unpoweredSurgeLoop;
+ sfxHandle_t powerSwitchSound;
+ sfxHandle_t powerZap[ 4 ];
+
+ //ckit's hacky dynamic display
+ qhandle_t ckitBackgroundShader; //note: supposed to be dynamic but I've got nothing put there yet
+ qhandle_t ckitOverlayShader;
+
+ qhandle_t ckit_background;
+ qhandle_t ckit_overlay;
+ qhandle_t ckit_bigicona;
+ qhandle_t ckit_bigiconb;
+ qhandle_t ckit_icon;
+ qhandle_t ckit_digit;
+
+ qhandle_t ckit_icon_bp;
+ qhandle_t ckit_icon_current;
+ qhandle_t ckit_icon_depth;
+ qhandle_t ckit_icon_health;
+ qhandle_t ckit_icon_height;
+ qhandle_t ckit_icon_network;
+ qhandle_t ckit_icon_nopower;
+ qhandle_t ckit_icon_nosurge;
+ qhandle_t ckit_icon_off;
+ qhandle_t ckit_icon_power;
+ qhandle_t ckit_icon_storedbp;
+ qhandle_t ckit_icon_surge;
+ qhandle_t ckit_icon_time;
+ qhandle_t ckit_icon_voltage;
+ qhandle_t ckit_icon_width;
+
+ qhandle_t ch_dot;
+ qhandle_t ch_dothit;
+ qhandle_t ch_circle;
+ qhandle_t ch_circlehit;
+ qhandle_t ch_friendly;
+
+ qhandle_t ch_adot;
+ qhandle_t ch_acircle;
+ qhandle_t ch_afriendly;
+ qhandle_t ch_aheadshot;
+
+ sfxHandle_t hitSound;
} cgMedia_t;
typedef struct
@@ -1425,7 +1511,6 @@ typedef struct
int timelimit;
int maxclients;
char mapname[ MAX_QPATH ];
- qboolean markDeconstruct; // Whether or not buildables are marked
int voteTime[ NUM_TEAMS ];
int voteYes[ NUM_TEAMS ];
@@ -1623,8 +1708,10 @@ extern vmCvar_t cg_chatTeamPrefix;
extern vmCvar_t cg_cuboidResizeAxis;
extern vmCvar_t cg_cuboidResizeRate;
extern vmCvar_t cg_cuboidPSQuality;
+
extern vmCvar_t cg_cuboidInfoX;
extern vmCvar_t cg_cuboidInfoY;
+extern vmCvar_t cg_drawCuboidInfo;
extern vmCvar_t cg_fuelInfoX;
extern vmCvar_t cg_fuelInfoY;
@@ -1634,6 +1721,11 @@ extern vmCvar_t cg_announcer;
extern vmCvar_t cg_cameraShakeMagnitude;
+extern vmCvar_t cg_debug1;
+extern vmCvar_t cg_debug2;
+extern vmCvar_t cg_debug3;
+extern vmCvar_t cg_debug4;
+
//
// cg_main.c
//
@@ -1753,15 +1845,16 @@ void CG_DrawBuildableStatus( void );
void CG_InitBuildables( void );
void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir );
void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir );
-void CG_CuboidAxis_f(void);
-void CG_CuboidRotate_f(void);
-void CG_CuboidSize_f(void);
-void CG_Cuboid_Send(void);
-void CG_Cuboid_Response(void);
+void CG_CuboidAxis_f( void );
+void CG_CuboidRotate_f( void );
+void CG_CuboidSize_f( void );
+void CG_Cuboid_Send( void );
+void CG_Cuboid_Response( void );
void CG_CuboidResize( qboolean enlarge );
-void CG_CuboidExplosion(buildable_t buildable, vec3_t origin, vec3_t cuboid);
-void CG_DrawCuboidParticles(void);
-void CG_CuboidAttack_f(void);
+void CG_CuboidExplosion( buildable_t buildable, vec3_t origin, vec3_t cuboid );
+void CG_DrawCuboidParticles( void );
+void CG_CuboidAttack_f( void );
+qhandle_t CG_BuildablePowerStatusIcon( entityState_t *es );
//
// cg_animation.c
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index ff3d567..ee37596 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -226,8 +226,10 @@ vmCvar_t cg_chatTeamPrefix;
vmCvar_t cg_cuboidResizeAxis;
vmCvar_t cg_cuboidResizeRate;
vmCvar_t cg_cuboidPSQuality;
+
vmCvar_t cg_cuboidInfoX;
vmCvar_t cg_cuboidInfoY;
+vmCvar_t cg_drawCuboidInfo;
vmCvar_t cg_fuelInfoX;
vmCvar_t cg_fuelInfoY;
@@ -237,6 +239,11 @@ vmCvar_t cg_announcer;
vmCvar_t cg_cameraShakeMagnitude;
+vmCvar_t cg_debug1;
+vmCvar_t cg_debug2;
+vmCvar_t cg_debug3;
+vmCvar_t cg_debug4;
+
typedef struct
{
vmCvar_t *vmCvar;
@@ -379,13 +386,19 @@ static cvarTable_t cvarTable[ ] =
{ &cg_cuboidInfoX, "cg_cuboidInfoX" ,"0", CVAR_ARCHIVE },
{ &cg_cuboidInfoY, "cg_cuboidInfoY" ,"150", CVAR_ARCHIVE },
+ { &cg_drawCuboidInfo, "cg_drawCuboidInfo" ,"0", CVAR_ARCHIVE },
{ &cg_fuelInfoX, "cg_fuelInfoX" ,"0", CVAR_ARCHIVE },
{ &cg_fuelInfoY, "cg_fuelInfoY" ,"150", CVAR_ARCHIVE },
{ &cg_fuelInfoScale, "cg_fuelInfoScale" ,"0.5", CVAR_ARCHIVE },
{ &cg_announcer, "cg_announcer", "1", CVAR_ARCHIVE },
- { &cg_cameraShakeMagnitude, "cg_cameraShakeMagnitude", "1", CVAR_ARCHIVE }
+ { &cg_cameraShakeMagnitude, "cg_cameraShakeMagnitude", "1", CVAR_ARCHIVE },
+
+ { &cg_debug1, "cg_debug1", "", CVAR_CHEAT },
+ { &cg_debug2, "cg_debug2", "", CVAR_CHEAT },
+ { &cg_debug3, "cg_debug3", "", CVAR_CHEAT },
+ { &cg_debug4, "cg_debug4", "", CVAR_CHEAT }
};
static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
@@ -745,6 +758,13 @@ static void CG_RegisterSounds( void )
cgs.media.cuboidResizeSoundB = trap_S_RegisterSound( "sound/cuboid/resizeb.wav", qfalse );
cgs.media.cuboidRotateSound = trap_S_RegisterSound( "sound/cuboid/rotate.wav", qfalse );
cgs.media.cuboidAxisChangeSound = trap_S_RegisterSound( "sound/cuboid/axischange.wav", qfalse );
+
+ cgs.media.unpoweredSurgeLoop = trap_S_RegisterSound( "sound/buildables/human/unpowered_surge.wav", qfalse );
+ cgs.media.powerSwitchSound = trap_S_RegisterSound( "sound/buildables/human/switch.wav", qfalse );
+ for( i = 0; i < 4; i++ )
+ cgs.media.powerZap[ i ] = trap_S_RegisterSound( va( "sound/buildables/human/powerzap%i.wav", i + 1 ), qfalse );
+
+ cgs.media.hitSound = trap_S_RegisterSound( "sound/feedback/hit.wav", qfalse );
}
@@ -776,6 +796,21 @@ static void CG_RegisterGraphics( void )
"gfx/2d/numbers/nine_32b",
"gfx/2d/numbers/minus_32b",
};
+ static char *sb_digital[ 12 ] =
+ {
+ "gfx/2d/digital/0",
+ "gfx/2d/digital/1",
+ "gfx/2d/digital/2",
+ "gfx/2d/digital/3",
+ "gfx/2d/digital/4",
+ "gfx/2d/digital/5",
+ "gfx/2d/digital/6",
+ "gfx/2d/digital/7",
+ "gfx/2d/digital/8",
+ "gfx/2d/digital/9",
+ "gfx/2d/digital/minus",
+ "gfx/2d/digital/comma"
+ };
static char *buildWeaponTimerPieShaders[ 8 ] =
{
"ui/assets/neutral/1_5pie",
@@ -797,6 +832,9 @@ static void CG_RegisterGraphics( void )
for( i = 0; i < 11; i++ )
cgs.media.numberShaders[ i ] = trap_R_RegisterShader( sb_nums[ i ] );
+
+ for( i = 0; i < 12; i++ )
+ cgs.media.digitalNumberShaders[ i ] = trap_R_RegisterShader( sb_digital[ i ] );
cgs.media.viewBloodShader = trap_R_RegisterShader( "gfx/damage/fullscreen_painblend" );
@@ -813,14 +851,13 @@ static void CG_RegisterGraphics( void )
cgs.media.backTileShader = trap_R_RegisterShader( "console" );
-
// building shaders
cgs.media.greenBuildShader = trap_R_RegisterShader("gfx/misc/greenbuild" );
cgs.media.redBuildShader = trap_R_RegisterShader("gfx/misc/redbuild" );
cgs.media.humanSpawningShader = trap_R_RegisterShader("models/buildables/telenode/rep_cyl" );
+ cgs.media.humanUnpoweredSpawningShader = trap_R_RegisterShader("gfx/misc/unpowered_prebuild" );
- for( i = 0; i < CUBOID_CRACK_TEXTURES - 1; i++ )
- cgs.media.cuboidCracks[ i ] = trap_R_RegisterShader( va( "models/cuboid/cracks_%i", i ) );
+ cgs.media.cuboidCracks = trap_R_RegisterShader( "models/cuboid/cracks" );
cgs.media.cuboidModel = trap_R_RegisterModel( "models/cuboid/cuboid.md3" );
cgs.media.cuboidRedBuildShader = trap_R_RegisterShader( "gfx/cuboid/build_red" );
@@ -832,9 +869,30 @@ static void CG_RegisterGraphics( void )
cg.waitForCB = qfalse;
cg.cuboidValid = qfalse;
cg.latestCBNumber = 0;
+ VectorSet( cg.cuboidSelection, 30, 30, 30 );
+
+ // ckit...
+ cgs.media.ckitBackgroundShader = trap_R_RegisterShader( "gfx/ckit/background" );
+ cgs.media.ckitOverlayShader = trap_R_RegisterShader( "gfx/ckit/overlay" );
+
+ cgs.media.ckit_icon_bp = trap_R_RegisterShader( "gfx/ckit/icon_bp" );
+ cgs.media.ckit_icon_current = trap_R_RegisterShader( "gfx/ckit/icon_current" );
+ cgs.media.ckit_icon_depth = trap_R_RegisterShader( "gfx/ckit/icon_depth" );
+ cgs.media.ckit_icon_health = trap_R_RegisterShader( "gfx/ckit/icon_health" );
+ cgs.media.ckit_icon_height = trap_R_RegisterShader( "gfx/ckit/icon_height" );
+ cgs.media.ckit_icon_network = trap_R_RegisterShader( "gfx/ckit/icon_network" );
+ cgs.media.ckit_icon_nopower = trap_R_RegisterShader( "gfx/ckit/icon_nopower" );
+ cgs.media.ckit_icon_nosurge = trap_R_RegisterShader( "gfx/ckit/icon_nosurge" );
+ cgs.media.ckit_icon_off = trap_R_RegisterShader( "gfx/ckit/icon_off" );
+ cgs.media.ckit_icon_power = trap_R_RegisterShader( "gfx/ckit/icon_power" );
+ cgs.media.ckit_icon_storedbp = trap_R_RegisterShader( "gfx/ckit/icon_storedbp" );
+ cgs.media.ckit_icon_surge = trap_R_RegisterShader( "gfx/ckit/icon_surge" );
+ cgs.media.ckit_icon_time = trap_R_RegisterShader( "gfx/ckit/icon_time" );
+ cgs.media.ckit_icon_voltage = trap_R_RegisterShader( "gfx/ckit/icon_voltage" );
+ cgs.media.ckit_icon_width = trap_R_RegisterShader( "gfx/ckit/icon_width" );
for( i = 0; i < 15; i++ )
- cgs.media.splashLogo[ i ] = trap_R_RegisterShader( va( "cuboid/logo_%i.tga", i ) );
+ cgs.media.splashLogo[ i ] = trap_R_RegisterShader( va( "cuboid/logo_%i.tga", i ) );
cgs.media.splashLeft = trap_R_RegisterShader( "cuboid/logo_left.tga" );
cgs.media.splashRight = trap_R_RegisterShader( "cuboid/logo_right.tga" );
@@ -845,6 +903,21 @@ static void CG_RegisterGraphics( void )
for( i = 0; i < 8; i++ )
cgs.media.buildWeaponTimerPie[ i ] = trap_R_RegisterShader( buildWeaponTimerPieShaders[ i ] );
+ cgs.media.friendlyCrosshair = trap_R_RegisterShader( "gfx/2d/crosshair_friendly.tga" );
+ cgs.media.hitCrosshair = trap_R_RegisterShader( "gfx/2d/crosshair_hit.tga" );
+
+ cgs.media.ch_dot = trap_R_RegisterShader( "gfx/2d/ch_dot.tga" );
+ cgs.media.ch_dothit = trap_R_RegisterShader( "gfx/2d/ch_dothit.tga" );
+ cgs.media.ch_circle = trap_R_RegisterShader( "gfx/2d/ch_circle.tga" );
+ cgs.media.ch_circlehit = trap_R_RegisterShader( "gfx/2d/ch_circlehit.tga" );
+ cgs.media.ch_friendly = trap_R_RegisterShader( "gfx/2d/ch_friendly.tga" );
+
+ cgs.media.ch_adot = trap_R_RegisterShader( "gfx/2d/ch_adot.tga" );
+ cgs.media.ch_acircle = trap_R_RegisterShader( "gfx/2d/ch_acircle.tga" );
+ cgs.media.ch_afriendly = trap_R_RegisterShader( "gfx/2d/ch_afriendly.tga" );
+ cgs.media.ch_aheadshot = trap_R_RegisterShader( "gfx/2d/ch_aheadshot.tga" );
+
+
// player health cross shaders
cgs.media.healthCross = trap_R_RegisterShader( "ui/assets/neutral/cross.tga" );
cgs.media.healthCross2X = trap_R_RegisterShader( "ui/assets/neutral/cross2.tga" );
@@ -885,6 +958,8 @@ static void CG_RegisterGraphics( void )
cgs.media.humanBuildableBleedPS = CG_RegisterParticleSystem( "humanBuildableBleedPS");
cgs.media.alienBuildableBleedPS = CG_RegisterParticleSystem( "alienBuildableBleedPS" );
+ cgs.media.humanPowerZapPS = CG_RegisterParticleSystem( "humanPowerZapPS" );
+
cgs.media.alienBleedPS = CG_RegisterParticleSystem( "alienBleedPS" );
cgs.media.humanBleedPS = CG_RegisterParticleSystem( "humanBleedPS" );
@@ -1010,6 +1085,13 @@ static void CG_RegisterClients( void )
cgs.media.jetpackFlashModel = trap_R_RegisterModel( "models/players/human_base/jetpack_flash.md3" );
cgs.media.battpackModel = trap_R_RegisterModel( "models/players/human_base/battpack.md3" );
+ cgs.media.ckit_background = trap_R_RegisterModel( "models/weapons/ckit/ckit_background.md3" );
+ cgs.media.ckit_overlay = trap_R_RegisterModel( "models/weapons/ckit/ckit_overlay.md3" );
+ cgs.media.ckit_bigicona = trap_R_RegisterModel( "models/weapons/ckit/ckit_bigicona.md3" );
+ cgs.media.ckit_bigiconb = trap_R_RegisterModel( "models/weapons/ckit/ckit_bigiconb.md3" );
+ cgs.media.ckit_icon = trap_R_RegisterModel( "models/weapons/ckit/ckit_icon.md3" );
+ cgs.media.ckit_digit = trap_R_RegisterModel( "models/weapons/ckit/ckit_digit.md3" );
+
cg.charModelFraction = 1.0f;
trap_UpdateScreen( );
diff --git a/src/cgame/cg_playerstate.c b/src/cgame/cg_playerstate.c
index 242a3bb..f7c8074 100644
--- a/src/cgame/cg_playerstate.c
+++ b/src/cgame/cg_playerstate.c
@@ -271,6 +271,12 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops )
last = cg.time;
}
}
+
+ if( ps->persistant[ PERS_HITS ] != ops->persistant[ PERS_HITS ] )
+ {
+ trap_S_StartSound( NULL, cg.predictedPlayerState.clientNum, CHAN_AUTO, cgs.media.hitSound );
+ cg.lastHitTime = cg.time;
+ }
// if we are going into the intermission, don't start any voices
if( cg.intermissionStarted )
diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c
index cf820c0..f9a173a 100644
--- a/src/cgame/cg_servercmds.c
+++ b/src/cgame/cg_servercmds.c
@@ -119,7 +119,6 @@ void CG_ParseServerinfo( void )
info = CG_ConfigString( CS_SERVERINFO );
cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
- cgs.markDeconstruct = atoi( Info_ValueForKey( info, "g_markDeconstruct" ) );
mapname = Info_ValueForKey( info, "mapname" );
Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
}
@@ -661,13 +660,9 @@ void CG_Menu( int menu, int arg )
//===============================
case MN_H_NOBP:
- if( cgs.markDeconstruct )
- longMsg = "There is no power remaining. Free up power by marking "
- "existing buildable objects.";
- else
- longMsg = "There is no power remaining. Free up power by deconstructing "
- "existing buildable objects.";
- shortMsg = "There is no power remaining";
+ longMsg = "You don't have enough build points. Acquire more of them from "
+ "a Factory.";
+ shortMsg = "Insufficient build points";
type = DT_BUILD;
break;
diff --git a/src/cgame/cg_tutorial.c b/src/cgame/cg_tutorial.c
index 212db33..cb596b9 100644
--- a/src/cgame/cg_tutorial.c
+++ b/src/cgame/cg_tutorial.c
@@ -202,27 +202,9 @@ static void CG_AlienBuilderText( char *text, playerState_t *ps )
if( ( es = CG_BuildableInRange( ps, NULL ) ) )
{
- if( cgs.markDeconstruct )
- {
- if( es->eFlags & EF_B_MARKED )
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to unmark this structure for replacement\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
- else
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to mark this structure for replacement\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
- }
- else
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to destroy this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to destroy this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
}
if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) == BA_NONE )
@@ -378,27 +360,9 @@ static void CG_HumanCkitText( char *text, playerState_t *ps )
if( ( es = CG_BuildableInRange( ps, NULL ) ) )
{
- if( cgs.markDeconstruct )
- {
- if( es->eFlags & EF_B_MARKED )
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to unmark this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
- else
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to mark this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
- }
- else
- {
- Q_strcat( text, MAX_TUTORIAL_TEXT,
- va( "Press %s to destroy this structure\n",
- CG_KeyNameForCommand( "deconstruct" ) ) );
- }
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to destroy this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
}
}
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index 7e22baf..b3dd4c7 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -605,15 +605,27 @@ static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi )
if( size < 0 )
size = 0;
+ wi->crossHairSize = size;
+
token = COM_Parse( &text_p );
if( !token )
break;
- wi->crossHair = trap_R_RegisterShader( token );
- wi->crossHairSize = size;
-
- if( !wi->crossHair )
- CG_Printf( S_COLOR_RED "ERROR: weapon crosshair not found %s\n", token );
+ if( !Q_stricmp( token, "none" ) )
+ wi->crossHairType = CH_NONE;
+ else if( !Q_stricmp( token, "dot" ) )
+ wi->crossHairType = CH_DOT;
+ else if( !Q_stricmp( token, "circle" ) )
+ wi->crossHairType = CH_CIRCLE;
+ else if( !Q_stricmp( token, "circleddot" ) )
+ wi->crossHairType = CH_CIRCLEDDOT;
+ else if( !Q_stricmp( token, "alien" ) )
+ wi->crossHairType = CH_ALIEN;
+ else
+ {
+ Com_Printf( S_COLOR_YELLOW "WARNING: unknown cross hair type '%s'\n", token );
+ wi->crossHairType = CH_NONE;
+ }
continue;
}
@@ -869,6 +881,180 @@ static float CG_MachinegunSpinAngle( centity_t *cent, qboolean firing )
return angle;
}
+/*
+=============
+CG_GenerateCKitDisplay
+
+Figures out what should be displayed on the CKit's display
+=============
+*/
+static void CG_GenerateCKitDisplay( void )
+{
+ int row = 0;
+ ckitDisplay_t *cd = &cg.ckitDisp;
+ entityState_t *es;
+ playerState_t *ps = &cg.predictedPlayerState;
+ qboolean target = qfalse; // true if looking at something
+ qboolean player = qfalse; // true if looking at a player (buildable otherwise)
+ int buildable; // buildable type
+ qboolean probing = qfalse; // measures voltages and currents
+ int powerNetwork;
+ int probeEntity;
+ qboolean building; // displays buildable's info
+ qboolean cuboid; // true if building cuboid
+ const buildableAttributes_t *battr;
+ int buildTimer;
+
+ memset( &cg.ckitDisp, 0, sizeof( cg.ckitDisp ) );
+
+ /*
+ part 1: figure out what we're dealing with
+ */
+
+ powerNetwork = ( ps->misc[ MISC_INFOHEAD ] & 1023 );
+
+ probeEntity = ( ps->misc[ MISC_INFOHEAD ] >> 10 ) & 1023;
+ if( probeEntity != 1023 )
+ {
+ target = qtrue;
+ if( probeEntity < MAX_CLIENTS )
+ {
+ target = qtrue;
+ player = qtrue;
+ probing = ( cg.crosshairClientNum == probeEntity );
+ }
+ else
+ probing = ( cg.crosshairBuildable == probeEntity );
+
+ es = &cg_entities[ probeEntity ].currentState;
+ }
+
+ buildable = cg.predictedPlayerState.stats[ STAT_BUILDABLE ] &~ SB_VALID_TOGGLEBIT;
+ building = ( buildable != BA_NONE );
+ if( building )
+ {
+ battr = BG_Buildable( buildable, cg.cuboidSelection );
+ cuboid = battr->cuboid;
+ }
+
+ buildTimer = ps->stats[ STAT_MISC ];
+
+ /*
+ part 2: set up icons & text
+ */
+
+ cd->background = cgs.media.ckitBackgroundShader;
+
+ // first big icon indicates if power is available
+ if( powerNetwork )
+ cd->bigicona = cgs.media.ckit_icon_power;
+ else
+ cd->bigicona = cgs.media.ckit_icon_nopower;
+
+ // second big icon always shows the building's state
+ if( target && !player )
+ cd->bigiconb = CG_BuildablePowerStatusIcon( es );
+
+ if( building )
+ {
+ if( cuboid )
+ {
+ //width
+ cd->lines[ row ].icon = cgs.media.ckit_icon_width;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", cg.cuboidSelection[ 0 ] );
+
+ //height
+ cd->lines[ row ].icon = cgs.media.ckit_icon_depth;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", cg.cuboidSelection[ 1 ] );
+
+ //depth
+ cd->lines[ row ].icon = cgs.media.ckit_icon_height;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", cg.cuboidSelection[ 2 ] );
+ }
+
+ //build points
+ cd->lines[ row ].icon = cgs.media.ckit_icon_bp;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", battr->buildPoints );
+
+ //health
+ cd->lines[ row ].icon = cgs.media.ckit_icon_health;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", battr->health );
+
+ //build time
+ cd->lines[ row ].icon = cgs.media.ckit_icon_time;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", 0.001f * battr->buildTime );
+ }
+ else
+ {
+ if( buildTimer )
+ {
+ //build timer
+ cd->lines[ row ].icon = cgs.media.ckit_icon_time;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", 0.001f * buildTimer );
+ }
+
+ // power network detector
+ cd->lines[ row ].icon = cgs.media.ckit_icon_network;
+ if( powerNetwork )
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", powerNetwork );
+ else
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "--------------------" );
+
+
+ if( target )
+ {
+ battr = BG_Buildable( es->modelindex, es->angles );
+
+ if( probing )
+ {
+ if( !player )
+ {
+ // ammeter
+ cd->lines[ row ].icon = cgs.media.ckit_icon_current;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.2f", 0.001f * ps->misc[ MISC_INFO1 ] );
+
+ // voltmeter
+ cd->lines[ row ].icon = cgs.media.ckit_icon_voltage;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.2f", 0.001f * ps->misc[ MISC_INFO2 ] );
+
+ // stored BP
+ if( BG_Buildable( es->modelindex, NULL )->hasStorage )
+ {
+ cd->lines[ row ].icon = cgs.media.ckit_icon_storedbp;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%.1f", 0.1f * ps->misc[ MISC_INFO3 ] );
+ }
+ }
+ else
+ {
+ // health
+ cd->lines[ row ].icon = cgs.media.ckit_icon_health;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", ps->misc[ MISC_INFO1 ] );
+
+ // stored BP
+ if( ps->misc[ MISC_INFO3 ] != -1 )
+ {
+ cd->lines[ row ].icon = cgs.media.ckit_icon_storedbp;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", ps->misc[ MISC_INFO2 ] );
+ }
+ }
+ }
+
+ if( !player )
+ {
+ //health
+ cd->lines[ row ].icon = cgs.media.ckit_icon_health;
+ if( battr->cuboid )
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", es->constantLight );
+ else
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", es->generic1 );
+
+ //build points
+ cd->lines[ row ].icon = cgs.media.ckit_icon_bp;
+ Com_sprintf( cd->lines[ row++ ].text, MAX_CKIT_TEXT, "%i", battr->buildPoints );
+ }
+ }
+ }
+}
/*
=============
@@ -1033,6 +1219,100 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
CG_DestroyParticleSystem( &cent->muzzlePS );
}
+ // NOTE: this thing is full of magic numbers - they were determined by trial and error, do not modify
+ if( ps && weaponNum == WP_HBUILD )
+ {
+ refEntity_t ent;
+ vec3_t origin;
+ float y;
+ int i, j, l;
+
+ CG_GenerateCKitDisplay( );
+
+ memset( &ent, 0, sizeof( ent ) );
+ ent.renderfx = parent->renderfx;
+ CG_PositionEntityOnTag( &ent, parent, parent->hModel, "tag_weapon" );
+
+ // offset it a bit
+ VectorMA( ent.origin, -0.1f, ent.axis[ 0 ], ent.origin );
+
+ // background
+ if( ( ent.customShader = cg.ckitDisp.background ) )
+ {
+ ent.hModel = cgs.media.ckit_background;
+ trap_R_AddRefEntityToScene( &ent );
+ }
+
+ // overlay
+ ent.hModel = cgs.media.ckit_overlay;
+ ent.customShader = cgs.media.ckitOverlayShader;
+ trap_R_AddRefEntityToScene( &ent );
+
+ // big icons
+ if( ( ent.customShader = cg.ckitDisp.bigicona ) )
+ {
+ ent.hModel = cgs.media.ckit_bigicona;
+ trap_R_AddRefEntityToScene( &ent );
+ }
+
+ if( ( ent.customShader = cg.ckitDisp.bigiconb ) )
+ {
+ ent.hModel = cgs.media.ckit_bigiconb;
+ trap_R_AddRefEntityToScene( &ent );
+ }
+
+ // backup the origin
+ VectorCopy( ent.origin, origin );
+
+ // draw all 6 rows
+ for( y = 0.0f, i = 0; i < MAX_CKIT_ROWS; i++, y += -0.48f )
+ {
+ VectorMA( origin, y * 0.42f, ent.axis[ 0 ], ent.origin );
+ VectorMA( ent.origin, y, ent.axis[ 2 ], ent.origin );
+
+ if( ( ent.customShader = cg.ckitDisp.lines[ i ].icon ) )
+ {
+ ent.hModel = cgs.media.ckit_icon;
+ trap_R_AddRefEntityToScene( &ent );
+ }
+
+ ent.hModel = cgs.media.ckit_digit;
+ l = strlen( cg.ckitDisp.lines[ i ].text );
+
+ if( l > MAX_CKIT_COLUMNS )
+ l = MAX_CKIT_COLUMNS;
+
+ VectorMA( ent.origin, -0.3f * ( MAX_CKIT_COLUMNS - l - 1 ), ent.axis[ 1 ], ent.origin );
+
+ for( j = 0; j < l && j < MAX_CKIT_COLUMNS; j++ )
+ {
+ int index;
+ char ch;
+
+ ch = cg.ckitDisp.lines[ i ].text[ j ];
+
+ if( ch >= '0' && ch <= '9' )
+ index = ch - '0';
+ else if( ch == '-' )
+ index = 10;
+ else if( ch == '.' )
+ index = 11;
+ else
+ index = 0;
+
+ if( random() > 0.995f )
+ {
+ index += (int)( random() * 11 );
+ index %= 11;
+ }
+
+ ent.customShader = cgs.media.digitalNumberShaders[ index ];
+ VectorMA( ent.origin, -0.3f, ent.axis[ 1 ], ent.origin );
+ trap_R_AddRefEntityToScene( &ent );
+ }
+ }
+ }
+
// add the flash
if( !weapon->wim[ weaponMode ].continuousFlash || !firing )
{
@@ -1124,7 +1404,7 @@ void CG_AddViewWeapon( playerState_t *ps )
weaponInfo_t *wi;
weapon_t weapon = ps->weapon;
weaponMode_t weaponMode = ps->generic1;
- vec3_t cuboidSize;
+ vec3_t cuboidSize;
// no weapon carried - can't draw it
if( weapon == WP_NONE )
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index a416ecb..ca443f2 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -69,7 +69,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
ASPAWN_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_OVERMIND, //int buildNum;
@@ -105,7 +106,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qtrue, //qboolean uniqueTest;
OVERMIND_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_BARRICADE, //int buildNum;
@@ -141,7 +143,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
BARRICADE_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_ACIDTUBE, //int buildNum;
@@ -177,7 +180,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
ACIDTUBE_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_TRAPPER, //int buildNum;
@@ -213,7 +217,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
TRAPPER_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_BOOSTER, //int buildNum;
@@ -250,7 +255,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
BOOSTER_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_HIVE, //int buildNum;
@@ -285,7 +291,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
HIVE_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_H_SPAWN, //int buildNum;
@@ -321,7 +328,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
HSPAWN_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_H_MGTURRET, //int buildNum;
@@ -357,7 +365,12 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
MGTURRET_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ MGTURRET_R_IDLE, //float resistance;
+ MGTURRET_R_ACTIVE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_TESLAGEN, //int buildNum;
@@ -393,7 +406,12 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
TESLAGEN_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ TESLAGEN_R_IDLE, //float resistance;
+ TESLAGEN_R_ACTIVE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_ARMOURY, //int buildNum;
@@ -429,7 +447,12 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
ARMOURY_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ ARMOURY_RESISTANCE, //float resistance;
+ ARMOURY_RESISTANCE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_DCC, //int buildNum;
@@ -465,7 +488,12 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
DC_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ DC_R_IDLE, //float resistance;
+ DC_R_ACTIVE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_MEDISTAT, //int buildNum;
@@ -502,20 +530,24 @@ static const buildableAttributes_t bg_buildableList[ ] =
qtrue, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
MEDISTAT_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ MEDISTAT_R_IDLE, //float resistance;
+ MEDISTAT_R_ACTIVE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_REACTOR, //int buildNum;
"reactor", //char *buildName;
"Reactor", //char *humanName;
- "All structures except the telenode rely on a reactor to operate. "
- "The reactor provides power for all the human structures either "
- "directly or via repeaters. Only one reactor can be built at a time.",
- "team_human_reactor", //char *entityName;
+ "A large nuclear generator, able to power substantial amounts of "
+ "structures.",
+ "team_human_reactor_big", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
REACTOR_BP, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S3 ), //int stages
REACTOR_HEALTH, //int health;
0, //int regenRate;
REACTOR_SPLASHDAMAGE, //int splashDamage;
@@ -536,9 +568,14 @@ static const buildableAttributes_t bg_buildableList[ ] =
0, //int creepSize;
qfalse, //qboolean dccTest;
qfalse, //qboolean transparentTest;
- qtrue, //qboolean uniqueTest;
+ qfalse, //qboolean uniqueTest;
REACTOR_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ qtrue, //qboolean isPowerSource;
+ qfalse, //qboolean requiresPower;
+ REACTOR_RESISTANCE, //float resistance;
+ REACTOR_RESISTANCE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
},
{
BA_H_REPEATER, //int buildNum;
@@ -574,7 +611,135 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
REPEATER_VALUE, //int value;
- qfalse //qboolean cuboid;
+ qfalse, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
+ },
+ {
+ BA_H_CAPBANK, //int buildNum;
+ "capbank", //char *buildName;
+ "Capacitor Bank", //char *humanName;
+ "A bank of capacitors able to compensate for "
+ "fluctations in the power network or even power "
+ "the network in the absence of a Reactor.",
+ "team_human_capbank", //char *entityName;
+ TR_GRAVITY, //trType_t traj;
+ 0.0, //float bounce;
+ CAPBANK_BP, //int buildPoints;
+ ( 1 << S2 )|( 1 << S3 ), //int stages
+ CAPBANK_HEALTH, //int health;
+ 0, //int regenRate;
+ CAPBANK_SPLASHDAMAGE, //int splashDamage;
+ CAPBANK_SPLASHRADIUS, //int splashRadius;
+ MOD_HSPAWN, //int meansOfDeath;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
+ BANIM_IDLE1, //int idleAnim;
+ 100, //int nextthink;
+ CAPBANK_BT, //int buildTime;
+ qtrue, //qboolean usable;
+ 0, //int turretRange;
+ 0, //int turretFireSpeed;
+ WP_NONE, //weapon_t turretProjType;
+ 0.95f, //float minNormal;
+ qfalse, //qboolean invertNormal;
+ qfalse, //qboolean creepTest;
+ 0, //int creepSize;
+ qfalse, //qboolean dccTest;
+ qfalse, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ CAPBANK_VALUE, //int value;
+ qfalse, //qboolean cuboid;
+ qtrue, //qboolean isPowerSource;
+ qfalse, //qboolean requiresPower;
+ CAPBANK_RESISTANCE, //float resistance;
+ CAPBANK_RESISTANCE, //float surgeResistance;
+ qfalse //qboolean hasStorage;
+ },
+ {
+ BA_H_RTG, //int buildNum;
+ "rtg", //char *buildName;
+ "RTG Unit", //char *humanName;
+ "A portable all-in-one device, featuring a "
+ "radioisotope thermoelectric generator and a "
+ "miniaturized version of the Refinery. Does not "
+ "require power to be built. ^2First RTG Unit does "
+ "not require build points!",
+ "team_human_reactor", //char *entityName;
+ TR_GRAVITY, //trType_t traj;
+ 0.0, //float bounce;
+ RTG_BP, //int buildPoints;
+ ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ RTG_HEALTH, //int health;
+ 0, //int regenRate;
+ RTG_SPLASHDAMAGE, //int splashDamage;
+ RTG_SPLASHRADIUS, //int splashRadius;
+ MOD_HSPAWN, //int meansOfDeath;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
+ BANIM_IDLE1, //int idleAnim;
+ 500, //int nextthink;
+ RTG_BT, //int buildTime;
+ qtrue, //qboolean usable;
+ 0, //int turretRange;
+ 0, //int turretFireSpeed;
+ WP_NONE, //weapon_t turretProjType;
+ 0.95f, //float minNormal;
+ qfalse, //qboolean invertNormal;
+ qfalse, //qboolean creepTest;
+ 0, //int creepSize;
+ qfalse, //qboolean dccTest;
+ qfalse, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ RTG_VALUE, //int value;
+ qfalse, //qboolean cuboid;
+ qtrue, //qboolean isPowerSource;
+ qfalse, //qboolean requiresPower;
+ RTG_RESISTANCE, //float resistance;
+ RTG_RESISTANCE, //float surgeResistance;
+ qtrue //qboolean hasStorage;
+ },
+ {
+ BA_H_REFINERY, //int buildNum;
+ "refinery", //char *buildName;
+ "Refinery", //char *humanName;
+ "A portable all-in-one device, featuring a "
+ "radioisotope thermoelectric generator and a "
+ "miniaturized version of the Refinery. Does not "
+ "require power to be built. ^1This is the first "
+ "buildable to be built.",
+ "team_human_refinery", //char *entityName;
+ TR_GRAVITY, //trType_t traj;
+ 0.0, //float bounce;
+ REFINERY_BP, //int buildPoints;
+ ( 1 << S2 )|( 1 << S3 ), //int stages
+ REFINERY_HEALTH, //int health;
+ 0, //int regenRate;
+ REFINERY_SPLASHDAMAGE, //int splashDamage;
+ REFINERY_SPLASHRADIUS, //int splashRadius;
+ MOD_HSPAWN, //int meansOfDeath;
+ TEAM_HUMANS, //int team;
+ ( 1 << WP_HBUILD ), //weapon_t buildWeapon;
+ BANIM_IDLE1, //int idleAnim;
+ 500, //int nextthink;
+ REFINERY_BT, //int buildTime;
+ qtrue, //qboolean usable;
+ 0, //int turretRange;
+ 0, //int turretFireSpeed;
+ WP_NONE, //weapon_t turretProjType;
+ 0.95f, //float minNormal;
+ qfalse, //qboolean invertNormal;
+ qfalse, //qboolean creepTest;
+ 0, //int creepSize;
+ qfalse, //qboolean dccTest;
+ qfalse, //qboolean transparentTest;
+ qfalse, //qboolean uniqueTest;
+ REFINERY_VALUE, //int value;
+ qfalse, //qboolean cuboid;
+ qfalse, //qboolean isPowerSource;
+ qtrue, //qboolean requiresPower;
+ REFINERY_R_IDLE, //float resistance;
+ REFINERY_R_ACTIVE, //float surgeResistance;
+ qtrue //qboolean hasStorage;
},
{
BA_H_CUBOID1, //int buildNum;
@@ -610,7 +775,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
0, //int value;
- qtrue //qboolean cuboid;
+ qtrue, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_H_CUBOID2, //int buildNum;
@@ -618,13 +784,13 @@ static const buildableAttributes_t bg_buildableList[ ] =
"Glass", //char *humanName;
"A cuboid made of a transparent chemical compound. "
"Its durability is low compared to other glass-like "
- "materials. However it has shown increased strenght "
+ "materials. However it has shown increased strength "
"when formed into a thin pane shape.",
"team_human_hcuboid2", //char *entityName;
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
0, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages
0, //int health;
0, //int regenRate;
0, //int splashDamage;
@@ -647,7 +813,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
0, //int value;
- qtrue //qboolean cuboid;
+ qtrue, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_H_CUBOID3, //int buildNum;
@@ -661,7 +828,7 @@ static const buildableAttributes_t bg_buildableList[ ] =
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
0, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S3 ), //int stages
0, //int health;
0, //int regenRate;
0, //int splashDamage;
@@ -684,7 +851,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
0, //int value;
- qtrue //qboolean cuboid;
+ qtrue, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_CUBOID1, //int buildNum;
@@ -720,7 +888,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
0, //int value;
- qtrue //qboolean cuboid;
+ qtrue, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
},
{
BA_A_CUBOID2, //int buildNum;
@@ -735,7 +904,7 @@ static const buildableAttributes_t bg_buildableList[ ] =
TR_GRAVITY, //trType_t traj;
0.0, //float bounce;
0, //int buildPoints;
- ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
+ ( 1 << S2 )|( 1 << S3 ), //int stages
0, //int health;
0, //int regenRate;
0, //int splashDamage;
@@ -758,7 +927,8 @@ static const buildableAttributes_t bg_buildableList[ ] =
qfalse, //qboolean transparentTest;
qfalse, //qboolean uniqueTest;
0, //int value;
- qtrue //qboolean cuboid;
+ qtrue, //qboolean cuboid;
+ DEFAULT_POWER_SETTINGS
}
};
@@ -1283,7 +1453,7 @@ static const classAttributes_t bg_classList[ ] =
80, //int steptime;
LEVEL2_SPEED, //float speed;
10.0f, //float acceleration;
- 3.0f, //float airAcceleration;
+ 2.0f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
380.0f, //float jumpMagnitude;
@@ -1310,7 +1480,7 @@ static const classAttributes_t bg_classList[ ] =
80, //int steptime;
LEVEL2_UPG_SPEED, //float speed;
10.0f, //float acceleration;
- 3.0f, //float airAcceleration;
+ 2.0f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
380.0f, //float jumpMagnitude;
@@ -1419,9 +1589,9 @@ static const classAttributes_t bg_classList[ ] =
0.002f, //float bob;
1.0f, //float bobCycle;
100, //int steptime;
- 1.0f, //float speed;
+ 1.1f, //float speed;
10.0f, //float acceleration;
- 1.0f, //float airAcceleration;
+ 1.5f, //float airAcceleration;
6.0f, //float friction;
100.0f, //float stopSpeed;
220.0f, //float jumpMagnitude;
@@ -4301,7 +4471,7 @@ const cuboidAttributes_t BG_CuboidTypes [] =
80, // float hppv
CBHPT_PLAIN, // int hpt
3.0, // float bppv
- 20, // int buildrate
+ 30, // int buildrate
5000, // int minbt
qfalse, // qboolean regen;
0, // int regenspeed
@@ -4325,7 +4495,7 @@ const cuboidAttributes_t BG_CuboidTypes [] =
52, // float hppv
CBHPT_PANES, // int hpt
1.5, // float bppv
- 15, // int buildrate
+ 25, // int buildrate
6500, // int minbt
qfalse, // qboolean regen;
0, // int regenspeed
@@ -4349,7 +4519,7 @@ const cuboidAttributes_t BG_CuboidTypes [] =
50, // float hppv
CBHPT_PLAIN, // int hpt
4.0, // float bppv
- 10, // int buildrate
+ 15, // int buildrate
8000, // int minbt
qfalse, // qboolean regen;
0, // int regenspeed
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index e06015d..cbaf90a 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -280,12 +280,11 @@ typedef enum
PERS_CREDIT, // human credit
PERS_QUEUEPOS, // position in the spawn queue
PERS_NEWWEAPON, // weapon to switch to
- PERS_BP,
- PERS_MARKEDBP,
+ PERS_BUILDPOINTS,
//zdrytchx: no space in stats, use persistant. This meanas we risk doing a double jump upon spawning but death animations are 1700 msecs long, so technically it's impossible anyway
PERS_JUMPTIME,
PERS_SPAWNS_IMPLANTED
- // netcode has space for 1 more
+ // netcode has space for 2 more
} persEnum_t;
#define PS_WALLCLIMBINGFOLLOW 0x00000001
@@ -293,6 +292,21 @@ typedef enum
#define PS_NONSEGMODEL 0x00000004
#define PS_SPRINTTOGGLE 0x00000008
+// player_state->misc[] indexes
+typedef enum
+{
+ MISC_INFOHEAD,
+ MISC_INFO1,
+ MISC_INFO2,
+ MISC_INFO3,
+
+ MISC_CUBOID_X,
+ MISC_CUBOID_Y,
+ MISC_CUBOID_Z
+
+ // netcode has space for 10 more
+} miscEnum_t;
+
// entityState_t->eFlags
// notice that some flags are overlapped, so their meaning depends on context
#define EF_DEAD 0x0001 // don't draw a foe marker over players with EF_DEAD
@@ -307,7 +321,7 @@ typedef enum
// buildable flags:
#define EF_B_SPAWNED 0x0008
#define EF_B_POWERED 0x0010
-#define EF_B_MARKED 0x0020
+#define EF_B_SURGE 0x0020 // note: enabled/disabled for Repeaters
#define EF_WARN_CHARGE 0x0020 // Lucifer Cannon is about to overcharge
#define EF_WALLCLIMB 0x0040 // wall walking
@@ -438,6 +452,10 @@ typedef enum
BA_H_REACTOR,
BA_H_REPEATER,
+ BA_H_CAPBANK,
+ BA_H_RTG,
+
+ BA_H_REFINERY,
//cuboids must stay in a block
#define CUBOID_FIRST BA_H_CUBOID1
@@ -581,7 +599,10 @@ typedef enum
EV_ALIEN_HATCH_FAILURE, // when it doesns't work
EV_JETPACK_DEACTIVATE,
- EV_JETPACK_REFUEL
+ EV_JETPACK_REFUEL,
+
+ EV_POWER_SWITCH,
+ EV_POWER_ZAP
} entity_event_t;
@@ -1068,9 +1089,17 @@ typedef struct
qboolean transparentTest;
qboolean uniqueTest;
- int value;
+ int value;
qboolean cuboid;
+
+ //power grid features
+ qboolean isPowerSource;
+ qboolean requiresPower;
+ float resistance;
+ float surgeResistance;
+
+ qboolean hasStorage;
} buildableAttributes_t;
typedef struct
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 1fa0caa..95f00d6 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -682,20 +682,6 @@ 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;
}
break;
@@ -780,6 +766,55 @@ void ClientTimerActions( gentity_t *ent, int msec )
ent->client->ps.stats[ STAT_SHAKE ] *= 0.77f;
if( ent->client->ps.stats[ STAT_SHAKE ] < 0 )
ent->client->ps.stats[ STAT_SHAKE ] = 0;
+
+ // update the currents and voltages
+ if( BG_GetPlayerWeapon( &client->ps ) == WP_HBUILD )
+ {
+ trace_t tr;
+ vec3_t viewOrigin, forward, end;
+ gentity_t *traceEnt;
+ int head_network = 0, head_entity = 1023;
+
+ BG_GetClientViewOrigin( &client->ps, viewOrigin );
+ AngleVectors( client->ps.viewangles, forward, NULL, NULL );
+ VectorMA( viewOrigin, 200, forward, end );
+
+ trap_Trace( &tr, viewOrigin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID );
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ head_network = ent->powerNetwork;
+
+ if( tr.fraction < 0.99f )
+ {
+ if( traceEnt->client )
+ {
+ if( traceEnt->client->pers.teamSelection == TEAM_HUMANS &&
+ traceEnt->client->ps.stats[ STAT_HEALTH ] >= 0 )
+ {
+ head_entity = traceEnt->s.number;
+ client->ps.misc[ MISC_INFO1 ] = traceEnt->client->ps.stats[ STAT_HEALTH ];
+
+ if( BG_GetPlayerWeapon( &traceEnt->client->ps ) == WP_HBUILD )
+ client->ps.misc[ MISC_INFO2 ] = traceEnt->client->ps.persistant[ PERS_BUILDPOINTS ];
+ else
+ client->ps.misc[ MISC_INFO2 ] = -1;
+ }
+ }
+ else if( traceEnt->s.eType == ET_BUILDABLE &&
+ traceEnt->health > 0 && traceEnt->buildableTeam == TEAM_HUMANS &&
+ ( traceEnt->isPowerSource || traceEnt->requiresPower ) )
+ {
+ head_network = traceEnt->powerNetwork;
+ head_entity = traceEnt->s.number;
+ client->ps.misc[ MISC_INFO1 ] = traceEnt->current * 1000;
+ client->ps.misc[ MISC_INFO2 ] = traceEnt->voltage * 1000;
+ client->ps.misc[ MISC_INFO3 ] = traceEnt->storedBP * 10;
+ }
+ }
+
+ client->ps.misc[ MISC_INFOHEAD ] = ( head_network & 1023 ) | ( head_entity & 1023 ) << 10;
+
+ }
}
while( client->time1000 >= 1000 )
@@ -1769,16 +1804,11 @@ void ClientThink_real( gentity_t *ent )
vec3_t eyes, view, point;
gentity_t *traceEnt;
-#define USE_OBJECT_RANGE 64
-
- int entityList[ MAX_GENTITIES ];
- vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
- vec3_t mins, maxs;
- int i, num;
+#define USE_OBJECT_RANGE 100
// look for object infront of player
AngleVectors( client->ps.viewangles, view, NULL, NULL );
- BG_GetClientViewOrigin( &client->ps, eyes ); // !@#CUBOID
+ BG_GetClientViewOrigin( &client->ps, eyes );
VectorMA( eyes, USE_OBJECT_RANGE, view, point );
trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
@@ -1786,50 +1816,29 @@ void ClientThink_real( gentity_t *ent )
if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- else
+ else if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
{
- //no entity in front of player - do a small area search
-
- VectorAdd( client->ps.origin, range, maxs );
- VectorSubtract( client->ps.origin, range, mins );
-
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
+ if( BG_AlienCanEvolve( client->ps.stats[ STAT_CLASS ],
+ client->pers.credit,
+ g_alienStage.integer ) )
{
- traceEnt = &g_entities[ entityList[ i ] ];
-
- if( traceEnt && traceEnt->buildableTeam == client->ps.stats[ STAT_TEAM ] && traceEnt->use )
- {
- traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context
- break;
- }
+ //no nearby objects and alien - show class menu
+ G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
}
-
- if( i == num && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ else
{
- if( BG_AlienCanEvolve( client->ps.stats[ STAT_CLASS ],
- client->pers.credit,
- g_alienStage.integer ) )
- {
- //no nearby objects and alien - show class menu
- G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
- }
- else
- {
- //flash frags
- G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
- }
+ //flash frags
+ G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 );
}
}
}
- client->ps.persistant[ PERS_BP ] = G_GetBuildPoints( client->ps.origin,
- client->ps.stats[ STAT_TEAM ] );
- client->ps.persistant[ PERS_MARKEDBP ] = G_GetMarkedBuildPoints( client->ps.origin,
- client->ps.stats[ STAT_TEAM ] );
-
- if( client->ps.persistant[ PERS_BP ] < 0 )
- client->ps.persistant[ PERS_BP ] = 0;
+ if( client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ {
+ client->ps.persistant[ PERS_BUILDPOINTS ] = G_GetBuildPoints( client->ps.origin, client->ps.stats[ STAT_TEAM ] );
+ if( client->ps.persistant[ PERS_BUILDPOINTS ] < 0 )
+ client->ps.persistant[ PERS_BUILDPOINTS ] = 0;
+ }
// perform once-a-second actions
ClientTimerActions( ent, msec );
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 0039ccd..8447e84 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -111,223 +111,6 @@ gentity_t *G_CheckSpawnPoint( int spawnNum, const vec3_t origin,
return NULL;
}
-#define POWER_REFRESH_TIME 2000
-
-/*
-================
-G_FindPower
-
-attempt to find power for self, return qtrue if successful
-================
-*/
-qboolean G_FindPower( gentity_t *self, qboolean searchUnspawned )
-{
- int i, j;
- gentity_t *ent, *ent2;
- gentity_t *closestPower = NULL;
- int distance = 0;
- int minDistance = REPEATER_BASESIZE + 1;
- vec3_t temp_v;
-
- if( self->buildableTeam != TEAM_HUMANS )
- return qfalse;
-
- // Reactor is always powered
- if( self->s.modelindex == BA_H_REACTOR )
- {
- self->parentNode = self;
-
- return qtrue;
- }
-
- // Handle repeaters
- if( self->s.modelindex == BA_H_REPEATER )
- {
- self->parentNode = G_Reactor( );
-
- return self->parentNode != NULL;
- }
-
- // Iterate through entities
- for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- 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 ) &&
- ( searchUnspawned || ent->spawned ) && ent->powered && ent->health > 0 )
- {
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
- distance = VectorLength( temp_v );
-
- // Always prefer a reactor if there is one in range
- if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE )
- {
- // Only power as much BP as the reactor can hold
- if( self->s.modelindex != BA_NONE )
- {
- int buildPoints = g_humanBuildPoints.integer;
-
- // Scan the buildables in the reactor zone
- for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ )
- {
- gentity_t *powerEntity;
-
- if( ent2->s.eType != ET_BUILDABLE )
- continue;
-
- if( ent2 == self )
- continue;
-
- powerEntity = ent2->parentNode;
-
- if( powerEntity && powerEntity->s.modelindex == BA_H_REACTOR && ( powerEntity == ent ) )
- {
- buildPoints -= BG_Buildable( ent2->s.modelindex, ent2->cuboidSize )->buildPoints;
- }
- }
-
- buildPoints -= level.humanBuildPointQueue;
-
- buildPoints -= BG_Buildable( self->s.modelindex, self->cuboidSize )->buildPoints;
-
- if( buildPoints >= 0 )
- {
- self->parentNode = ent;
- return qtrue;
- }
- else
- {
- // a buildable can still be built if it shares BP from two zones
-
- // TODO: handle combined power zones here
- }
- }
-
- // Dummy buildables don't need to look for zones
- else
- {
- self->parentNode = ent;
- return qtrue;
- }
- }
- else if( distance < minDistance )
- {
- // It's a repeater, so check that enough BP will be available to power
- // the buildable but only if self is a real buildable
-
- if( self->s.modelindex != BA_NONE )
- {
- int buildPoints = g_humanRepeaterBuildPoints.integer;
-
- // Scan the buildables in the repeater zone
- for( j = MAX_CLIENTS, ent2 = g_entities + j; j < level.num_entities; j++, ent2++ )
- {
- gentity_t *powerEntity;
-
- if( ent2->s.eType != ET_BUILDABLE )
- continue;
-
- if( ent2 == self )
- continue;
-
- powerEntity = ent2->parentNode;
-
- if( powerEntity && powerEntity->s.modelindex == BA_H_REPEATER && ( powerEntity == ent ) )
- {
- buildPoints -= BG_Buildable( ent2->s.modelindex, ent->cuboidSize )->buildPoints;
- }
- }
-
- if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active )
- buildPoints -= level.buildPointZones[ ent->buildPointZone ].queuedBuildPoints;
-
- buildPoints -= BG_Buildable( self->s.modelindex, self->cuboidSize )->buildPoints;
-
- if( buildPoints >= 0 )
- {
- closestPower = ent;
- minDistance = distance;
- }
- else
- {
- // a buildable can still be built if it shares BP from two zones
-
- // TODO: handle combined power zones here
- }
- }
- else
- {
- // Dummy buildables don't need to look for zones
- closestPower = ent;
- minDistance = distance;
- }
- }
- }
- }
-
- self->parentNode = closestPower;
- return self->parentNode != NULL;
-}
-
-/*
-================
-G_PowerEntityForPoint
-
-Simple wrapper to G_FindPower to find the entity providing
-power for the specified point
-================
-*/
-gentity_t *G_PowerEntityForPoint( const vec3_t origin )
-{
- gentity_t dummy;
-
- dummy.parentNode = NULL;
- dummy.buildableTeam = TEAM_HUMANS;
- dummy.s.modelindex = BA_NONE;
- VectorCopy( origin, dummy.s.origin );
-
- if( G_FindPower( &dummy, qfalse ) )
- return dummy.parentNode;
- else
- return NULL;
-}
-
-/*
-================
-G_PowerEntityForEntity
-
-Simple wrapper to G_FindPower to find the entity providing
-power for the specified entity
-================
-*/
-gentity_t *G_PowerEntityForEntity( gentity_t *ent )
-{
- if( G_FindPower( ent, qfalse ) )
- return ent->parentNode;
- return NULL;
-}
-
-/*
-================
-G_IsPowered
-
-Check if a location has power, returning the entity type
-that is providing it
-================
-*/
-buildable_t G_IsPowered( vec3_t origin )
-{
- gentity_t *ent = G_PowerEntityForPoint( origin );
-
- if( ent )
- return ent->s.modelindex;
- else
- return BA_NONE;
-}
-
-
/*
==================
G_GetBuildPoints
@@ -347,95 +130,36 @@ int G_GetBuildPoints( const vec3_t pos, team_t team )
}
else if( team == TEAM_HUMANS )
{
- gentity_t *powerPoint = G_PowerEntityForPoint( pos );
-
- if( powerPoint && powerPoint->s.modelindex == BA_H_REACTOR )
- return level.humanBuildPoints;
-
- if( powerPoint && powerPoint->s.modelindex == BA_H_REPEATER &&
- powerPoint->usesBuildPointZone && level.buildPointZones[ powerPoint->buildPointZone ].active )
- {
- return level.buildPointZones[ powerPoint->buildPointZone ].totalBuildPoints -
- level.buildPointZones[ powerPoint->buildPointZone ].queuedBuildPoints;
- }
-
- // Return the BP of the main zone by default
- return level.humanBuildPoints;
+ return 0xDEADBEE; //humans use the material system
}
return 0;
}
/*
-==================
-G_GetMarkedBuildPoints
+================
+G_IsDCCBuilt
-Get the number of marked build points from a position
-==================
+See if any powered DCC exists
+================
*/
-int G_GetMarkedBuildPoints( const vec3_t pos, team_t team )
+qboolean G_IsDCCBuilt( void )
{
- gentity_t *ent;
int i;
- int sum = 0;
-
- if( G_TimeTilSuddenDeath( ) <= 0 )
- return 0;
-
- if( !g_markDeconstruct.integer )
- return 0;
-
- for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- if( team == TEAM_HUMANS &&
- ent->s.modelindex != BA_H_REACTOR &&
- ent->s.modelindex != BA_H_REPEATER &&
- ent->parentNode != G_PowerEntityForPoint( pos ) )
- continue;
-
- if( !ent->inuse )
- continue;
-
- if( ent->health <= 0 )
- continue;
-
- if( ent->buildableTeam != team )
- continue;
-
- if( ent->deconstruct )
- sum += BG_Buildable( ent->s.modelindex, ent->cuboidSize )->buildPoints;
- }
-
- return sum;
-}
-
-/*
-==================
-G_InPowerZone
-
-See if a buildable is inside of another power zone.
-Return pointer to provider if so.
-It's different from G_FindPower because FindPower for
-providers will find themselves.
-(This doesn't check if power zones overlap)
-==================
-*/
-gentity_t *G_InPowerZone( gentity_t *self )
-{
- int i;
- gentity_t *ent;
- int distance;
- vec3_t temp_v;
+ gentity_t *ent;
+ static gentity_t *cache = NULL;
+
+ if( cache && cache->inuse && cache->s.eType == ET_BUILDABLE &&
+ cache->s.modelindex == BA_H_DCC && cache->spawned &&
+ cache->powered && cache->health >= 0 )
+ return qtrue;
for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( ent == self )
+ if( ent->s.modelindex != BA_H_DCC )
continue;
if( !ent->spawned )
@@ -443,81 +167,46 @@ gentity_t *G_InPowerZone( gentity_t *self )
if( ent->health <= 0 )
continue;
+
+ if( !ent->powered )
+ 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 ) &&
- ent->spawned && ent->powered )
- {
- VectorSubtract( self->s.origin, ent->s.origin, temp_v );
- distance = VectorLength( temp_v );
+ cache = ent;
- if( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE )
- return ent;
- else if( ent->s.modelindex == BA_H_REPEATER && distance <= REPEATER_BASESIZE )
- return ent;
- }
+ return qtrue;
}
- return NULL;
+ return qfalse;
}
-/*
-================
-G_FindDCC
-
-attempt to find a controlling DCC for self, return number found
-================
-*/
-int G_FindDCC( gentity_t *self )
-{
- int i;
- gentity_t *ent;
- int distance = 0;
- vec3_t temp_v;
- int foundDCC = 0;
-
- if( self->buildableTeam != TEAM_HUMANS )
- return 0;
-
- //iterate through entities
- for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities && foundDCC < MAX_DCS_PER_BUILDABLE; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- //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 );
- if( distance < DC_RANGE && ent->powered )
- {
- foundDCC++;
- }
- }
- }
-
- return foundDCC;
-}
/*
================
-G_IsDCCBuilt
+G_IsRTGBuilt
-See if any powered DCC exists
+See if any RTG exists
================
*/
-qboolean G_IsDCCBuilt( void )
+qboolean G_IsRTGBuilt( void )
{
int i;
gentity_t *ent;
+ static gentity_t *cache = NULL;
+
+ if( cache && cache->inuse && cache->s.eType == ET_BUILDABLE &&
+ cache->s.modelindex == BA_H_DCC && cache->spawned &&
+ cache->health >= 0 )
+ return qtrue;
for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
+ if( !ent->r.linked )
+ continue;
+
if( ent->s.eType != ET_BUILDABLE )
continue;
- if( ent->s.modelindex != BA_H_DCC )
+ if( ent->s.modelindex != BA_H_RTG )
continue;
if( !ent->spawned )
@@ -526,6 +215,8 @@ qboolean G_IsDCCBuilt( void )
if( ent->health <= 0 )
continue;
+ cache = ent;
+
return qtrue;
}
@@ -534,33 +225,17 @@ qboolean G_IsDCCBuilt( void )
/*
================
-G_Reactor
G_Overmind
-Since there's only one of these and we quite often want to find them, cache the
-results, but check them for validity each time
+Since there's only one overmind and we quite often want to find it, cache the
+results, but check it for validity each time
-The code here will break if more than one reactor or overmind is allowed, even
+The code here will break if more than one overmind is allowed, even
if one of them is dead/unspawned
================
*/
static gentity_t *G_FindBuildable( buildable_t buildable );
-gentity_t *G_Reactor( void )
-{
- static gentity_t *rc;
-
- // If cache becomes invalid renew it
- if( !rc || rc->s.eType != ET_BUILDABLE || rc->s.modelindex != BA_H_REACTOR )
- rc = G_FindBuildable( BA_H_REACTOR );
-
- // If we found it and it's alive, return it
- if( rc && rc->spawned && rc->health > 0 )
- return rc;
-
- return NULL;
-}
-
gentity_t *G_Overmind( void )
{
static gentity_t *om;
@@ -698,6 +373,457 @@ static void G_CreepSlow( gentity_t *self )
/*
================
+G_ScanPowerGrid
+
+Recursively finds all power entities reachable from the specified entity
+================
+*/
+static struct
+{
+ int networkID;
+
+ gentity_t *load[ MAX_GENTITIES ];
+ int loadCount;
+
+ gentity_t *sources[ MAX_GENTITIES ];
+ int sourceCount;
+
+ qboolean visited[ MAX_GENTITIES ];
+} grid;
+
+void G_ScanPowerGrid( gentity_t *this )
+{
+ int i;
+ int nextList[ MAX_GENTITIES ], nextCount;
+ gentity_t *next;
+ vec3_t mins, maxs;
+ float range;
+
+ switch( this->s.modelindex )
+ {
+ case BA_H_REACTOR:
+ case BA_H_CAPBANK:
+ case BA_H_RTG:
+ range = REACTOR_BASESIZE;
+ break;
+ case BA_H_REPEATER:
+ range = REPEATER_BASESIZE;
+ break;
+ }
+
+ for( i = 0; i < 3; i++ )
+ {
+ mins[ i ] = this->s.origin[ i ] - range;
+ maxs[ i ] = this->s.origin[ i ] + range;
+ }
+
+ nextCount = trap_EntitiesInBox( mins, maxs, nextList, MAX_GENTITIES );
+
+ for( i = 0; i < nextCount; i++ )
+ {
+ if( grid.visited[ nextList[ i ] ] )
+ continue;
+ grid.visited[ nextList[ i ] ] = qtrue;
+
+ next = g_entities + nextList[ i ];
+
+ if( next->s.eType != ET_BUILDABLE )
+ {
+ //let ckits know in which network's range they're in
+ if( next->client &&
+ next->health >= 0 &&
+ next->s.weapon == WP_HBUILD )
+ next->powerNetwork = grid.networkID;
+ continue;
+ }
+
+ if( next->health <= 0 )
+ continue;
+ if( next->buildableTeam != TEAM_HUMANS )
+ continue;
+
+ //repeater just extends the power grid
+ //it does not provide or consume power
+ if( next->spawned && next->s.modelindex == BA_H_REPEATER )
+ {
+ //switched off
+ if( !next->active )
+ continue;
+
+ next->powerNetwork = grid.networkID;
+ G_ScanPowerGrid( next );
+ continue;
+ }
+
+ if( !next->isPowerSource && !next->requiresPower )
+ continue;
+
+ next->powerNetwork = grid.networkID;
+ if( next->isPowerSource )
+ {
+ //switched off
+ if( !next->active )
+ continue;
+ grid.sources[ grid.sourceCount++ ] = next;
+ }
+ else
+ grid.load[ grid.loadCount++ ] = next;
+ }
+}
+
+
+/*
+================
+G_CalculatePowerGrid
+
+This function takes the listed power sources (with voltages V and
+internal resistances Rs) and load (with resistances R), constructs the
+following electrical circuit and solves it:
+
+ Legend:
+ -(-+)-- voltage source
+ -/\/\/- resistor
+ |- ground
+
+ V1 Rs1 I1 R1
+ +--(-+)--/\/\/-->-+ +--/\/\/--+
+ | V2 Rs2 I2| I | R2 |
+ |--+--(-+)--/\/\/-->-+-->--+--/\/\/--+--|
+ | | | |
+ ... ... ... ...
+ | Vn Rsn In| | Rn |
+ +--(-+)--/\/\/-->-+ +--/\/\/--+
+
+================
+*/
+void G_CalculatePowerGrid( void )
+{
+ int i, j;
+ gentity_t *ent;
+
+ float nGl, nGs, nG, nR;
+ float URs, U2, Is;
+
+ // the net load conductance (resistors in parallel)
+ for( nGl = 0.0f, i = 0; i < grid.loadCount; i++ )
+ nGl += 1.0f / grid.load[ i ]->resistance;
+
+ // the net source conductance (resistors in parallel)
+ for( nGs = 0.0f, i = 0; i < grid.sourceCount; i++ )
+ nGs += 1.0f / grid.sources[ i ]->resistance;
+
+ // solve the circuit using the superposition theorem
+ for( i = 0; i < grid.sourceCount; i++ )
+ {
+ ent = grid.sources[ i ];
+
+ // net load + other sources conductance
+ nG = nGl + nGs - 1.0f / ent->resistance;
+
+ // net resistance
+ nR = 1.0f / nG + ent->resistance;
+
+ // current flowing through the source
+ Is = ent->voltage / nR;
+ ent->current += ent->voltage / nR;
+
+ // voltage drop on source's internal resistance
+ URs = Is * ent->resistance;
+
+ // voltage drop on other sources or the entire load
+ U2 = ent->voltage - URs;
+
+ // current flowing through other sources
+ for( j = 0; j < grid.sourceCount; j++ )
+ if( i != j )
+ grid.sources[ j ]->current -= U2 / grid.sources[ j ]->resistance;
+
+ // current flowing through parts of the load
+ for( j = 0; j < grid.loadCount; j++ )
+ grid.load[ j ]->current += U2 / grid.load[ j ]->resistance;
+ }
+}
+
+/*
+================
+G_UpdatePowerGrid
+
+Recalculate the entire power grid
+================
+*/
+void G_UpdatePowerGrid( float dt )
+{
+ int i;
+ gentity_t *ent;
+
+ // reset all ckits
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ g_entities[ i ].powerNetwork = 0;
+
+ // reset all power entities
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ ent = g_entities + i;
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+ if( ent->buildableTeam != TEAM_HUMANS )
+ continue;
+
+ ent->powerNetwork = 0;
+ ent->current = 0.0f;
+
+ if( !ent->spawned )
+ {
+ ent->resistance = PREBUILD_RESISTANCE;
+ continue;
+ }
+
+ if( ent->s.modelindex == BA_H_REACTOR ||
+ ent->s.modelindex == BA_H_RTG )
+ ent->voltage = POWER_VOLTAGE * g_voltageModifier.value;
+
+ if( !ent->requiresPower || ent->isPowerSource )
+ continue;
+
+ if( ent->surge )
+ ent->resistance = BG_Buildable( ent->s.modelindex, NULL )->surgeResistance;
+ else
+ ent->resistance = BG_Buildable( ent->s.modelindex, NULL )->resistance;
+ }
+
+ // this table will be used throughout the following loop and its recursive calls
+ memset( grid.visited, 0, sizeof( grid.visited ) );
+
+ // find an unvisited power source and make a list of all power sources
+ // and receivers reachable from it for G_CalculatePowerGrid
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ if( grid.visited[ i ] )
+ continue;
+
+ ent = g_entities + i;
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+ if( !ent->spawned )
+ continue;
+ if( ent->health <= 0 )
+ continue;
+ if( ent->buildableTeam != TEAM_HUMANS )
+ continue;
+ if( !ent->isPowerSource )
+ continue;
+ if( !ent->active )
+ continue;
+
+ // unique network id
+ grid.networkID = ent->s.number;
+ ent->powerNetwork = grid.networkID;
+
+ // traverse the world and find all reachable power entities
+ grid.loadCount = 0;
+ grid.sourceCount = 0;
+
+ // add this source to the list
+ grid.visited[ i ] = qtrue;
+ grid.sources[ grid.sourceCount++ ] = ent;
+
+ // scan recursively
+ G_ScanPowerGrid( ent );
+
+ // calculate the power grid
+ G_CalculatePowerGrid( );
+ }
+
+ // calculate voltages, power levels, etc.
+ for( i = MAX_CLIENTS; i < level.num_entities; i++ )
+ {
+ ent = g_entities + i;
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+ if( ent->buildableTeam != TEAM_HUMANS )
+ continue;
+
+ if( ent->isPowerSource )
+ {
+ if( ent->active && ent->s.modelindex == BA_H_CAPBANK )
+ ent->voltage -= ent->current * dt / CAPBANK_CAPACITY;
+
+ //zapping effect
+ #define MIN_ZAP_CURRENT 2.0f
+ #define ZAP_CHANCE_FACTOR 0.01f
+ if( ent->current > MIN_ZAP_CURRENT )
+ {
+ float chance;
+
+ chance = ( ent->current - MIN_ZAP_CURRENT ) * ZAP_CHANCE_FACTOR;
+ if( chance > 0.2f )
+ chance = 0.2f;
+
+ chance = 1.0f - chance;
+ if( random() > chance )
+ G_AddEvent( ent, EV_POWER_ZAP, 0 );
+ }
+ }
+ else
+ ent->voltage = ent->current * ent->resistance;
+ }
+}
+
+/*
+================
+G_SetupPowerEntity
+
+Called when a Human buildable finishes spawning and needs power grid
+related variables to be set accordingly
+================
+*/
+void G_SetupPowerEntity( gentity_t *built )
+{
+ built->requiresPower = BG_Buildable( built->s.modelindex, NULL )->requiresPower;
+ built->isPowerSource = BG_Buildable( built->s.modelindex, NULL )->isPowerSource;
+ built->resistance = BG_Buildable( built->s.modelindex, NULL )->resistance;
+
+ if( built->isPowerSource )
+ {
+ switch( built->s.modelindex )
+ {
+ case BA_H_REACTOR:
+ built->resistance = REACTOR_RESISTANCE;
+ break;
+ case BA_H_CAPBANK:
+ built->voltage = 0.0f; //spawn discharged
+ built->resistance = CAPBANK_RESISTANCE;
+ case BA_H_RTG:
+ built->resistance = RTG_RESISTANCE;
+ break;
+ }
+ }
+}
+
+/*
+================
+G_PowerForPoint
+
+Returns to which network ID this point belongs
+================
+*/
+
+int G_PowerForPoint( vec3_t point )
+{
+ int i;
+ int list[ MAX_GENTITIES ], count;
+ gentity_t *ent;
+ vec3_t mins, maxs;
+ float range;
+/*
+ switch( this->s.modelindex )
+ {
+
+ }*/
+ range = REACTOR_BASESIZE;
+
+ for( i = 0; i < 3; i++ )
+ {
+ mins[ i ] = point[ i ] - range;
+ maxs[ i ] = point[ i ] + range;
+ }
+
+ count = trap_EntitiesInBox( mins, maxs, list, MAX_GENTITIES );
+
+ for( i = 0; i < count; i++ )
+ {
+ ent = g_entities + list[ i ];
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+ if( ent->buildableTeam != TEAM_HUMANS )
+ continue;
+ if( ent->health <= 0 )
+ continue;
+ if( !ent->spawned )
+ continue;
+ if( !ent->powerNetwork )
+ continue;
+
+ switch( ent->s.modelindex )
+ {
+ case BA_H_REACTOR:
+ case BA_H_CAPBANK:
+ case BA_H_RTG:
+ range = REACTOR_BASESIZE;
+ break;
+ case BA_H_REPEATER:
+ range = REPEATER_BASESIZE;
+ break;
+ default:
+ continue;
+ }
+
+ if( Distance( ent->s.origin, point ) > range )
+ continue;
+
+ return ent->powerNetwork;
+ }
+ return 0;
+}
+
+/*
+================
+NOTES TO G_CheckPower AND G_Surge
+
+Make sure that a buildable's resistance NEVER depends on its power
+state. Failure to ensure that will result in feedback loops in the
+power grid and general weirdness.
+================
+*/
+
+/*
+================
+G_CheckPower
+
+(Helper for Human buildable think functions)
+Checks if there's enough power for the buildable to idle
+================
+*/
+qboolean G_CheckPower( gentity_t *self, float min_current )
+{
+ self->surge = qfalse;
+ self->surgePowered = qfalse;
+ self->powered = qtrue;
+
+ if( self->current < min_current )
+ {
+ self->powered = qfalse;
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+================
+G_Surge
+
+(Helper for Human buildable think functions)
+Checks if there's enough power for the buildable to perform its action
+================
+*/
+qboolean G_Surge( gentity_t *self, float surge_current )
+{
+ self->surge = qtrue;
+
+ if( self->current < surge_current )
+ return qfalse;
+
+ self->surgePowered = qtrue;
+ return qtrue;
+}
+
+/*
+================
nullDieFunction
hack to prevent compilers complaining about function pointer -> NULL conversion
@@ -1536,42 +1662,6 @@ void ATrapper_Think( gentity_t *self )
//==================================================================================
-
-
-
-/*
-================
-G_SuicideIfNoPower
-
-Destroy human structures that have been unpowered too long
-================
-*/
-static qboolean G_SuicideIfNoPower( gentity_t *self )
-{
- if( self->buildableTeam != TEAM_HUMANS )
- return qfalse;
-
- if( !self->powered )
- {
- // if the power hasn't reached this buildable for some time, then destroy the buildable
- if( self->count == 0 )
- self->count = level.time;
- else if( ( level.time - self->count ) >= HUMAN_BUILDABLE_INACTIVE_TIME )
- {
- if( self->parentNode )
- G_Damage( self, NULL, g_entities + self->parentNode->killedBy,
- NULL, NULL, self->health, 0, MOD_NOCREEP );
- else
- G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_NOCREEP );
- return qtrue;
- }
- }
- else
- self->count = 0;
-
- return qfalse;
-}
-
/*
================
G_IdlePowerState
@@ -1594,13 +1684,9 @@ static void G_IdlePowerState( gentity_t *self )
}
-
-
//==================================================================================
-
-
/*
================
HSpawn_Disappear
@@ -1666,7 +1752,6 @@ void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
self->die = nullDieFunction;
self->killedBy = attacker - g_entities;
- self->powered = qfalse; //free up power
self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
if( self->spawned )
@@ -1694,36 +1779,30 @@ void HSpawn_Think( gentity_t *self )
{
gentity_t *ent;
- // set parentNode
- self->powered = G_FindPower( self, qfalse );
-
- if( G_SuicideIfNoPower( self ) )
+ if( !self->spawned || self->health <= 0 )
return;
-
- if( self->spawned )
+
+ //only suicide if at rest
+ if( self->s.groundEntityNum )
{
- //only suicide if at rest
- if( self->s.groundEntityNum )
+ if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin,
+ self->s.origin2, BA_H_SPAWN, NULL ) ) != NULL )
{
- if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin,
- self->s.origin2, BA_H_SPAWN, NULL ) ) != NULL )
+ // If the thing blocking the spawn is a buildable, kill it.
+ // If it's part of the map, kill self.
+ if( ent->s.eType == ET_BUILDABLE )
{
- // If the thing blocking the spawn is a buildable, kill it.
- // If it's part of the map, kill self.
- if( ent->s.eType == ET_BUILDABLE )
- {
- G_Damage( ent, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
- G_SetBuildableAnim( self, BANIM_SPAWN1, qtrue );
- }
- else if( ent->s.number == ENTITYNUM_WORLD || ent->s.eType == ET_MOVER )
- {
- G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
- return;
- }
-
- if( ent->s.eType == ET_CORPSE )
- G_FreeEntity( ent ); //quietly remove
+ G_Damage( ent, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ G_SetBuildableAnim( self, BANIM_SPAWN1, qtrue );
+ }
+ else if( ent->s.number == ENTITYNUM_WORLD || ent->s.eType == ET_MOVER )
+ {
+ G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ return;
}
+
+ if( ent->s.eType == ET_CORPSE )
+ G_FreeEntity( ent ); //quietly remove
}
}
@@ -1735,7 +1814,25 @@ void HSpawn_Think( gentity_t *self )
//==================================================================================
+/*
+================
+HRepeater_Think
+
+Think function for Human Repeater
+================
+*/
+void HRepeater_Think( gentity_t *self )
+{
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
+
+ if( !self->spawned || self->health <= 0 )
+ return;
+
+ self->powered = self->active && ( self->powerNetwork != 0 );
+
+ G_IdlePowerState( self );
+}
/*
@@ -1752,7 +1849,6 @@ static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *att
self->die = nullDieFunction;
self->killedBy = attacker - g_entities;
- self->powered = qfalse; //free up power
self->s.eFlags &= ~EF_FIRING; //prevent any firing effects
if( self->spawned )
@@ -1767,83 +1863,34 @@ static void HRepeater_Die( gentity_t *self, gentity_t *inflictor, gentity_t *att
}
G_LogDestruction( self, attacker, mod );
-
- if( self->usesBuildPointZone )
- {
- buildPointZone_t *zone = &level.buildPointZones[self->buildPointZone];
-
- zone->active = qfalse;
- self->usesBuildPointZone = qfalse;
- }
}
/*
================
-HRepeater_Think
+HSwitchable_Use
-Think for human power repeater
+Use for switchable buildings
================
*/
-void HRepeater_Think( gentity_t *self )
+void HSwitchable_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
- int i;
- gentity_t *powerEnt;
- buildPointZone_t *zone;
-
- self->powered = G_FindPower( self, qfalse );
-
- powerEnt = G_InPowerZone( self );
- if( powerEnt != NULL )
- {
- // If the repeater is inside of another power zone then suicide
- // Attribute death to whoever built the reactor if that's a human,
- // which will ensure that it does not queue the BP
- if( powerEnt->builtBy >= 0 )
- G_Damage( self, NULL, g_entities + powerEnt->builtBy, NULL, NULL, self->health, 0, MOD_SUICIDE );
- else
- G_Damage( self, NULL, NULL, NULL, NULL, self->health, 0, MOD_SUICIDE );
+ if( !self->spawned || self->health <= 0 )
return;
- }
-
- G_IdlePowerState( self );
- // Initialise the zone once the repeater has spawned
- if( self->spawned && ( !self->usesBuildPointZone || !level.buildPointZones[ self->buildPointZone ].active ) )
+ if( !other || !other->client )
+ return;
+
+ // ckits and blasters switch the building
+ if( other->s.weapon == WP_HBUILD ||
+ other->s.weapon == WP_BLASTER )
{
- // See if a free zone exists
- for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ )
- {
- zone = &level.buildPointZones[ i ];
-
- if( !zone->active )
- {
- // Initialise the BP queue with no BP queued
- zone->queuedBuildPoints = 0;
- zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer;
- zone->nextQueueTime = level.time;
- zone->active = qtrue;
-
- self->buildPointZone = zone - level.buildPointZones;
- self->usesBuildPointZone = qtrue;
-
- break;
- }
- }
+ self->active ^= 1;
+ G_AddEvent( self, EV_POWER_SWITCH, 0 );
+ return;
}
- self->nextthink = level.time + POWER_REFRESH_TIME;
-}
-
-/*
-================
-HRepeater_Use
-
-Use for human power repeater
-================
-*/
-void HRepeater_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
-{
- if( self->health <= 0 || !self->spawned )
+ // not powered
+ if( !self->powerNetwork )
return;
if( other && other->client )
@@ -1869,8 +1916,16 @@ void HReactor_Think( gentity_t *self )
vec3_t mins, maxs;
int i, num;
gentity_t *enemy, *tent;
+ qboolean fired = qfalse;
+
+ if( !self->spawned || self->health <= 0 )
+ return;
- if( self->dcc )
+ self->powered = self->active;
+
+ G_IdlePowerState( self );
+
+ if( G_IsDCCBuilt( ) )
{
VectorAdd( self->s.origin, dccrange, maxs );
VectorSubtract( self->s.origin, dccrange, mins );
@@ -1881,54 +1936,62 @@ void HReactor_Think( gentity_t *self )
VectorSubtract( self->s.origin, range, mins );
}
- if( self->spawned && ( self->health > 0 ) )
+ // Creates a tesla trail for every target
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- qboolean fired = qfalse;
-
- // Creates a tesla trail for every target
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- enemy = &g_entities[ entityList[ i ] ];
- if( !enemy->client ||
- enemy->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
- continue;
- if( enemy->flags & FL_NOTARGET )
- continue;
+ enemy = &g_entities[ entityList[ i ] ];
+ if( !enemy->client ||
+ enemy->client->ps.stats[ STAT_TEAM ] != TEAM_ALIENS )
+ continue;
+ if( enemy->flags & FL_NOTARGET )
+ continue;
- tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
- tent->s.generic1 = self->s.number; //src
- tent->s.clientNum = enemy->s.number; //dest
- VectorCopy( self->s.pos.trBase, tent->s.origin2 );
- fired = qtrue;
- }
+ tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL );
+ tent->s.generic1 = self->s.number; //src
+ tent->s.clientNum = enemy->s.number; //dest
+ VectorCopy( self->s.pos.trBase, tent->s.origin2 );
+ fired = qtrue;
+ }
- // Actual damage is done by radius
- if( fired )
- {
- self->timestamp = level.time;
- if( self->dcc )
- G_SelectiveRadiusDamage( self->s.pos.trBase, self,
- REACTOR_ATTACK_DCC_DAMAGE,
- REACTOR_ATTACK_DCC_RANGE, self,
- MOD_REACTOR, TEAM_HUMANS );
- else
- G_SelectiveRadiusDamage( self->s.pos.trBase, self,
- REACTOR_ATTACK_DAMAGE,
- REACTOR_ATTACK_RANGE, self,
- MOD_REACTOR, TEAM_HUMANS );
- }
+ // Actual damage is done by radius
+ if( fired )
+ {
+ self->timestamp = level.time;
+ if( G_IsDCCBuilt( ) )
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DCC_DAMAGE,
+ REACTOR_ATTACK_DCC_RANGE, self,
+ MOD_REACTOR, TEAM_HUMANS );
+ else
+ G_SelectiveRadiusDamage( self->s.pos.trBase, self,
+ REACTOR_ATTACK_DAMAGE,
+ REACTOR_ATTACK_RANGE, self,
+ MOD_REACTOR, TEAM_HUMANS );
}
- if( self->dcc )
- self->nextthink = level.time + REACTOR_ATTACK_DCC_REPEAT;
- else
- self->nextthink = level.time + REACTOR_ATTACK_REPEAT;
+ if( G_IsDCCBuilt( ) )
+ self->nextthink -= REACTOR_ATTACK_DCC_REPEAT - REACTOR_ATTACK_REPEAT;
}
//==================================================================================
+/*
+================
+HArmoury_Think
+*
+Think function for Human Armoury
+================
+*/
+void HArmoury_Think( gentity_t *self )
+{
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
+
+ if( !self->spawned )
+ return;
+ G_CheckPower( self, ARMOURY_CURRENT );
+}
/*
================
@@ -1953,57 +2016,9 @@ void HArmoury_Activate( gentity_t *self, gentity_t *other, gentity_t *activator
}
}
-/*
-================
-HArmoury_Think
-
-Think for armoury
-================
-*/
-void HArmoury_Think( gentity_t *self )
-{
- //make sure we have power
- self->nextthink = level.time + POWER_REFRESH_TIME;
-
- self->powered = G_FindPower( self, qfalse );
-
- G_SuicideIfNoPower( self );
-}
-
-
-
-
-//==================================================================================
-
-
-
-
-
-/*
-================
-HDCC_Think
-
-Think for dcc
-================
-*/
-void HDCC_Think( gentity_t *self )
-{
- //make sure we have power
- self->nextthink = level.time + POWER_REFRESH_TIME;
-
- self->powered = G_FindPower( self, qfalse );
-
- G_SuicideIfNoPower( self );
-}
-
-
-
-
//==================================================================================
-
-
/*
================
HMedistat_Die
@@ -2037,10 +2052,12 @@ void HMedistat_Think( gentity_t *self )
qboolean occupied = qfalse;
self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
-
- self->powered = G_FindPower( self, qfalse );
- if( G_SuicideIfNoPower( self ) )
+
+ if( !self->spawned || self->health <= 0 )
return;
+
+ G_CheckPower( self, MEDISTAT_I_IDLE );
+
G_IdlePowerState( self );
//clear target's healing flag
@@ -2055,105 +2072,105 @@ void HMedistat_Think( gentity_t *self )
self->active = qfalse;
self->enemy = NULL;
}
-
- self->nextthink = level.time + POWER_REFRESH_TIME;
- return;
}
- if( self->spawned )
+ 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 );
+
+ //check if a previous occupier is still here
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
{
- VectorAdd( self->s.origin, self->r.maxs, maxs );
- VectorAdd( self->s.origin, self->r.mins, mins );
+ player = &g_entities[ entityList[ i ] ];
- mins[ 2 ] += fabs( self->r.mins[ 2 ] ) + self->r.maxs[ 2 ];
- maxs[ 2 ] += 60; //player height
+ if( player->flags & FL_NOTARGET )
+ continue; // notarget cancels even beneficial effects?
+
+ //remove poison from everyone, not just the healed player
+ if( player->client && player->client->ps.stats[ STAT_STATE ] & SS_POISONED )
+ player->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+
+ if( self->enemy == player && player->client &&
+ ( ( player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) &&
+ player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ PM_Live( player->client->ps.pm_type ) ) )
+ {
+ if( !G_Surge( self, MEDISTAT_I_ACTIVE ) )
+ return;
- //if active use the healing idle
- if( self->active )
- G_SetIdleBuildableAnim( self, BANIM_IDLE2 );
-
- //check if a previous occupier is still here
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ occupied = qtrue;
+ player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
+ }
+ }
+
+ if( !occupied )
+ {
+ self->enemy = NULL;
+
+ //look for something to heal
for( i = 0; i < num; i++ )
{
player = &g_entities[ entityList[ i ] ];
if( player->flags & FL_NOTARGET )
continue; // notarget cancels even beneficial effects?
-
- //remove poison from everyone, not just the healed player
- if( player->client && player->client->ps.stats[ STAT_STATE ] & SS_POISONED )
- player->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
-
- if( self->enemy == player && player->client &&
- ( (player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) && // DIFF NOTE: remove this change from diffs ASAP
- player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
- PM_Live( player->client->ps.pm_type ) ) )
- {
- occupied = qtrue;
- player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
- }
- }
-
- if( !occupied )
- {
- self->enemy = NULL;
- //look for something to heal
- for( i = 0; i < num; i++ )
+ if( player->client && player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- player = &g_entities[ entityList[ i ] ];
-
- if( player->flags & FL_NOTARGET )
- continue; // notarget cancels even beneficial effects?
-
- if( player->client && player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ if( ( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] ||
+ player->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX ) &&
+ PM_Live( player->client->ps.pm_type ) )
{
- if( ( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] ||
- player->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX ) &&
- PM_Live( player->client->ps.pm_type ) )
+ if( !G_Surge( self, MEDISTAT_I_ACTIVE ) )
+ return;
+
+ self->enemy = player;
+
+ //start the heal anim
+ if( !self->active && self->surge && self->surgePowered )
{
- self->enemy = player;
-
- //start the heal anim
- if( !self->active )
- {
- G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
- self->active = qtrue;
- player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
- }
+ G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ self->active = qtrue;
+ player->client->ps.stats[ STAT_STATE ] |= SS_HEALING_ACTIVE;
}
- else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) )
- BG_AddUpgradeToInventory( UP_MEDKIT, player->client->ps.stats );
}
+ else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) )
+ BG_AddUpgradeToInventory( UP_MEDKIT, player->client->ps.stats );
}
}
+ }
- //nothing left to heal so go back to idling
- if( !self->enemy && self->active )
- {
- G_SetBuildableAnim( self, BANIM_CONSTRUCT2, qtrue );
- G_SetIdleBuildableAnim( self, BANIM_IDLE1 );
+ //nothing left to heal so go back to idling
+ if( !self->enemy && self->active )
+ {
+ G_SetBuildableAnim( self, BANIM_CONSTRUCT2, qtrue );
+ G_SetIdleBuildableAnim( self, BANIM_IDLE1 );
- self->active = qfalse;
- }
- else if( self->enemy && self->enemy->client ) //heal!
- {
- if( self->enemy->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX )
- self->enemy->client->ps.stats[ STAT_STAMINA ] += STAMINA_MEDISTAT_RESTORE;
+ self->active = qfalse;
+ }
+ else if( self->enemy && self->enemy->client ) //heal!
+ {
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] += STAMINA_MEDISTAT_RESTORE;
- if( self->enemy->client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
- self->enemy->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
- self->enemy->health++;
+ self->enemy->health++;
- //if they're completely healed, give them a medkit
- if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] )
- {
- self->enemy->health = self->enemy->client->ps.stats[ STAT_MAX_HEALTH ];
- if( !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) )
- BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats );
- }
+ //if they're completely healed, give them a medkit
+ if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] )
+ {
+ self->enemy->health = self->enemy->client->ps.stats[ STAT_MAX_HEALTH ];
+ if( !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) )
+ BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats );
}
}
}
@@ -2179,8 +2196,8 @@ qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target,
trace_t tr;
vec3_t dir, end;
- if( !target || target->health <= 0 || !target->client ||
- target->client->pers.teamSelection != TEAM_ALIENS )
+ if( !target || target->health <= 0 || !target->client /*||
+ target->client->pers.teamSelection != TEAM_ALIENS */) //debug: target humans too for now
return qfalse;
if( target->flags & FL_NOTARGET )
@@ -2368,6 +2385,7 @@ HMGTurret_Think
Think function for MG turret
================
*/
+
void HMGTurret_Think( gentity_t *self )
{
self->nextthink = level.time +
@@ -2375,10 +2393,12 @@ void HMGTurret_Think( gentity_t *self )
// Turn off client side muzzle flashes
self->s.eFlags &= ~EF_FIRING;
-
- self->powered = G_FindPower( self, qfalse );
- if( G_SuicideIfNoPower( self ) )
+
+ if( !self->spawned || self->health <= 0 )
return;
+
+ G_CheckPower( self, MGTURRET_I_IDLE );
+
G_IdlePowerState( self );
// If not powered or spawned don't do anything
@@ -2386,10 +2406,9 @@ void HMGTurret_Think( gentity_t *self )
{
// if power loss drop turret
if( self->spawned &&
- HMGTurret_State( self, MGT_STATE_INACTIVE ) )
+ HMGTurret_State( self, MGT_STATE_INACTIVE ) );
return;
- self->nextthink = level.time + POWER_REFRESH_TIME;
return;
}
if( !self->spawned )
@@ -2428,6 +2447,9 @@ void HMGTurret_Think( gentity_t *self )
if( !self->active || self->turretSpinupTime > level.time )
return;
+ if( !G_Surge( self, MGTURRET_I_ACTIVE ) )
+ return;
+
// Fire repeat delay
if( self->timestamp > level.time )
return;
@@ -2456,62 +2478,174 @@ Think function for Tesla Generator
*/
void HTeslaGen_Think( gentity_t *self )
{
+ vec3_t origin, range, mins, maxs;
+ int entityList[ MAX_GENTITIES ], i, num;
+
self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
- self->powered = G_FindPower( self, qfalse );
- if( G_SuicideIfNoPower( self ) )
+ if( !self->spawned || self->health <= 0 )
return;
+
+ G_CheckPower( self, TESLAGEN_I_IDLE );
+
G_IdlePowerState( self );
//if not powered don't do anything and check again for power next think
if( !self->powered )
{
self->s.eFlags &= ~EF_FIRING;
- self->nextthink = level.time + POWER_REFRESH_TIME;
return;
}
- if( self->spawned && self->timestamp < level.time )
- {
- vec3_t origin, range, mins, maxs;
- int entityList[ MAX_GENTITIES ], i, num;
+ if( !self->spawned )
+ return;
- // Communicates firing state to client
- self->s.eFlags &= ~EF_FIRING;
+ // Communicates firing state to client
+ self->s.eFlags &= ~EF_FIRING;
- // Move the muzzle from the entity origin up a bit to fire over turrets
- VectorMA( self->s.origin, self->r.maxs[ 2 ], self->s.origin2, origin );
+ // Move the muzzle from the entity origin up a bit to fire over turrets
+ VectorMA( self->s.origin, self->r.maxs[ 2 ], self->s.origin2, origin );
- VectorSet( range, TESLAGEN_RANGE, TESLAGEN_RANGE, TESLAGEN_RANGE );
- VectorAdd( origin, range, maxs );
- VectorSubtract( origin, range, mins );
+ VectorSet( range, TESLAGEN_RANGE, TESLAGEN_RANGE, TESLAGEN_RANGE );
+ VectorAdd( origin, range, maxs );
+ VectorSubtract( origin, range, mins );
- // Attack nearby Aliens
- num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
- for( i = 0; i < num; i++ )
- {
- self->enemy = &g_entities[ entityList[ i ] ];
+ // Attack nearby Aliens
+ num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
+ for( i = 0; i < num; i++ )
+ {
+ self->enemy = &g_entities[ entityList[ i ] ];
- if( self->enemy->flags & FL_NOTARGET )
- continue;
+ if( self->enemy->flags & FL_NOTARGET )
+ continue;
+
+ if( self->enemy->client && self->enemy->health > 0 &&
+ /*self->enemy->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS &&*/
+ Distance( origin, self->enemy->s.pos.trBase ) <= TESLAGEN_RANGE )
+ {
+ if( !G_Surge( self, TESLAGEN_I_ACTIVE ) )
+ break;
- if( self->enemy->client && self->enemy->health > 0 &&
- self->enemy->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS &&
- Distance( origin, self->enemy->s.pos.trBase ) <= TESLAGEN_RANGE )
- FireWeapon( self );
+ FireWeapon( self );
}
- self->enemy = NULL;
+ }
+ self->enemy = NULL;
- if( self->s.eFlags & EF_FIRING )
- {
- G_AddEvent( self, EV_FIRE_WEAPON, 0 );
+ if( self->s.eFlags & EF_FIRING )
+ {
+ G_AddEvent( self, EV_FIRE_WEAPON, 0 );
- //doesn't really need an anim
- //G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
+ //doesn't really need an anim
+ //G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
- self->timestamp = level.time + TESLAGEN_REPEAT;
- }
+ self->timestamp = level.time + TESLAGEN_REPEAT;
+ }
+}
+
+//==================================================================================
+
+void HDCC_Think( gentity_t *self )
+{
+ int i, count, list[ MAX_GENTITIES ];
+ gentity_t *ent;
+ vec3_t mins, maxs;
+
+ self->nextthink = level.time + DC_HEALRATE;
+
+ if( !self->spawned || self->health <= 0 )
+ return;
+
+ G_CheckPower( self, DC_I_IDLE );
+ G_IdlePowerState( self );
+ if( !self->powered )
+ return;
+
+ for( i = 0; i < 3; i++ )
+ mins[ i ] = self->s.origin[ i ] - DC_RANGE,
+ maxs[ i ] = self->s.origin[ i ] + DC_RANGE;
+
+ count = trap_EntitiesInBox( mins, maxs, list, MAX_GENTITIES );
+
+ for( i = 0; i < count; i++ )
+ {
+ ent = g_entities + list[ i ];
+
+ if( ent->s.eType != ET_BUILDABLE )
+ continue;
+ if( ent->buildableTeam != TEAM_HUMANS )
+ continue;
+ if( ent->health >= BG_Buildable( ent->s.modelindex, ent->cuboidSize )->health )
+ continue;
+ if( ent->lastDamageTime + HUMAN_REGEN_DAMAGE_TIME >= level.time )
+ continue;
+ if( BG_Buildable( ent->s.modelindex, NULL )->cuboid &&
+ !BG_CuboidAttributes( ent->s.modelindex )->repairable )
+ continue;
+
+ if( !G_Surge( self, DC_I_ACTIVE ) )
+ return;
+
+ ent->health++;
+ }
+}
+
+//==================================================================================
+
+void HCapbank_Think( gentity_t *self)
+{
+ //nothing to do here
+}
+
+//==================================================================================
+
+void HRTG_Think( gentity_t *self)
+{
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
+
+ if( !self->spawned || self->health <= 0 )
+ return;
+
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ {
+ self->storedBP = 0;
+ return;
}
+
+ self->storedBP += RTG_YIELD * g_massYieldModifier.value;
+
+ if( self->storedBP > RTG_STORAGE )
+ self->storedBP = RTG_STORAGE;
+}
+
+//==================================================================================
+
+void HRefinery_Think( gentity_t *self)
+{
+ self->nextthink = level.time + BG_Buildable( self->s.modelindex, NULL )->nextthink;
+
+ if( !self->spawned || self->health <= 0 )
+ return;
+
+ G_CheckPower( self, REFINERY_I_IDLE );
+ G_IdlePowerState( self );
+
+ if( G_TimeTilSuddenDeath( ) <= 0 )
+ {
+ self->storedBP = 0;
+ return;
+ }
+
+ //nothing to do
+ if( self->storedBP >= REFINERY_STORAGE - 0.001f )
+ return;
+
+ if( !G_Surge( self, REFINERY_I_ACTIVE ) )
+ return;
+
+ self->storedBP += REFINERY_YIELD * g_massYieldModifier.value;
+
+ if( self->storedBP > REFINERY_STORAGE )
+ self->storedBP = REFINERY_STORAGE;
}
//==================================================================================
@@ -2534,7 +2668,6 @@ void Cuboid_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
G_SetBuildableAnim( self, BANIM_DESTROY1, qtrue ); // just for sound
self->die = nullDieFunction;
self->killedBy = attacker - g_entities;
- self->powered = qfalse;
self->s.eFlags &= ~EF_FIRING;
G_LogDestruction( self, attacker, mod );
dir[ 0 ] =
@@ -2632,48 +2765,6 @@ void G_QueueBuildPoints( gentity_t *self )
level.alienBuildPointQueue += queuePoints;
break;
-
- case TEAM_HUMANS:
- powerEntity = G_PowerEntityForEntity( self );
-
- if( powerEntity )
- {
- int nqt;
- switch( powerEntity->s.modelindex )
- {
- case BA_H_REACTOR:
- nqt = G_NextQueueTime( level.humanBuildPointQueue,
- g_humanBuildPoints.integer,
- g_humanBuildQueueTime.integer );
- if( !level.humanBuildPointQueue ||
- level.time + nqt < level.humanNextQueueTime )
- level.humanNextQueueTime = level.time + nqt;
-
- level.humanBuildPointQueue += queuePoints;
- break;
-
- case BA_H_REPEATER:
- if( powerEntity->usesBuildPointZone &&
- level.buildPointZones[ powerEntity->buildPointZone ].active )
- {
- buildPointZone_t *zone = &level.buildPointZones[ powerEntity->buildPointZone ];
-
- nqt = G_NextQueueTime( zone->queuedBuildPoints,
- zone->totalBuildPoints,
- g_humanRepeaterBuildQueueTime.integer );
-
- if( !zone->queuedBuildPoints ||
- level.time + nqt < zone->nextQueueTime )
- zone->nextQueueTime = level.time + nqt;
-
- zone->queuedBuildPoints += queuePoints;
- }
- break;
-
- default:
- break;
- }
- }
}
}
@@ -2774,6 +2865,7 @@ void G_BuildableThink( gentity_t *ent, int msec )
{
G_TeamCommand( TEAM_ALIENS, "cp \"The Overmind has awakened!\"" );
}
+ G_SetupPowerEntity( ent );
}
// Timer actions
@@ -2784,9 +2876,18 @@ void G_BuildableThink( gentity_t *ent, int msec )
if( !ent->spawned )
{
- buildRate=(int)(ceil((float)maxHealth/(float)buildTime*1e3f));
- ent->health=MIN(ent->health+buildRate,maxHealth);
- ent->healthLeft=MAX(ent->healthLeft-buildRate,0);
+ buildRate = (int)( ceil( (float)maxHealth / (float)buildTime * 1.0e3f ) );
+
+ if( ent->buildableTeam == TEAM_HUMANS &&
+ ent->s.modelindex != BA_H_RTG )
+ {
+ buildRate *= ent->current / PREBUILD_CURRENT;
+ if( buildRate < 0 )
+ buildRate = 0;
+ ent->powered = ( buildRate > 0 );
+ }
+ ent->health = MIN( ent->health + buildRate, maxHealth );
+ ent->healthLeft = MAX( ent->healthLeft - buildRate, 0 );
}
else if( ent->health > 0 && ent->health < maxHealth )
{
@@ -2795,13 +2896,6 @@ void G_BuildableThink( gentity_t *ent, int msec )
{
ent->health += regenRate;
}
- else if( ent->buildableTeam == TEAM_HUMANS && ent->dcc &&
- ( ent->lastDamageTime + HUMAN_REGEN_DAMAGE_TIME ) < level.time &&
- ( !BG_Buildable( ent->s.modelindex, NULL )->cuboid ||
- BG_CuboidAttributes( ent->s.modelindex )->repairable ) )
- {
- ent->health += DC_HEALRATE * ent->dcc;
- }
}
if( ent->health >= maxHealth )
@@ -2819,8 +2913,6 @@ void G_BuildableThink( gentity_t *ent, int msec )
if( ent->clientSpawnTime < 0 )
ent->clientSpawnTime = 0;
- ent->dcc = ( ent->buildableTeam != TEAM_HUMANS ) ? 0 : G_FindDCC( ent );
-
// Set health
ent->s.generic1 = MIN( MAX( ent->health, 0 ), 999 );
@@ -2828,16 +2920,47 @@ void G_BuildableThink( gentity_t *ent, int msec )
BG_CuboidPackHealthSafe( ent->s.modelindex, &ent->s, ent->health );
// Set flags
- ent->s.eFlags &= ~( EF_B_POWERED | EF_B_SPAWNED | EF_B_MARKED );
- if( ent->powered )
- ent->s.eFlags |= EF_B_POWERED;
+ ent->s.eFlags &= ~( EF_B_POWERED | EF_B_SPAWNED | EF_B_SURGE );
+
+ if( ent->buildableTeam == TEAM_HUMANS )
+ {
+ if( ent->s.modelindex == BA_H_REPEATER )
+ {
+ if( ent->powered )
+ ent->s.eFlags |= EF_B_POWERED;
+ if( ent->active )
+ ent->s.eFlags |= EF_B_SURGE;
+ }
+ else if( ent->isPowerSource )
+ {
+ ent->s.eFlags |= EF_B_POWERED;
+ if( ent->active )
+ ent->s.eFlags |= EF_B_SURGE;
+ }
+ else
+ {
+ if( ent->powered )
+ {
+ if( ent->surge )
+ {
+ ent->s.eFlags |= EF_B_SURGE;
+ if( ent->surgePowered )
+ ent->s.eFlags |= EF_B_POWERED;
+ }
+ else
+ ent->s.eFlags |= EF_B_POWERED;
+ }
+ }
+ }
+ else
+ {
+ if( ent->powered )
+ ent->s.eFlags |= EF_B_POWERED;
+ }
if( ent->spawned )
ent->s.eFlags |= EF_B_SPAWNED;
- if( ent->deconstruct )
- ent->s.eFlags |= EF_B_MARKED;
-
// Check if this buildable is touching any triggers
G_BuildableTouchTriggers( ent );
@@ -2940,450 +3063,61 @@ static qboolean G_BuildablesIntersect( buildable_t a, vec3_t originA, vec3_t cub
/*
===============
-G_CompareBuildablesForRemoval
-
-qsort comparison function for a buildable removal list
-===============
-*/
-static buildable_t cmpBuildable;
-static vec3_t cmpOrigin;
-static vec3_t cmpCuboid;
-static int G_CompareBuildablesForRemoval( const void *a, const void *b )
-{
- int precedence[ ] =
- {
- BA_NONE,
-
- BA_A_BARRICADE,
- BA_A_ACIDTUBE,
- BA_A_TRAPPER,
- BA_A_HIVE,
- BA_A_BOOSTER,
- BA_A_SPAWN,
- BA_A_CUBOID1,
- BA_A_OVERMIND,
-
- BA_H_MGTURRET,
- BA_H_TESLAGEN,
- BA_H_DCC,
- BA_H_MEDISTAT,
- BA_H_ARMOURY,
- BA_H_SPAWN,
- BA_H_REPEATER,
- BA_H_CUBOID1,
- BA_H_CUBOID2,
- BA_H_REACTOR
- };
-
- gentity_t *buildableA, *buildableB;
- int i;
- int aPrecedence = 0, bPrecedence = 0;
- qboolean aMatches = qfalse, bMatches = qfalse;
-
- buildableA = *(gentity_t **)a;
- buildableB = *(gentity_t **)b;
-
- // Prefer the one that collides with the thing we're building
- aMatches = G_BuildablesIntersect( cmpBuildable, cmpOrigin, cmpCuboid,
- buildableA->s.modelindex, buildableA->s.origin, buildableA->cuboidSize );
- bMatches = G_BuildablesIntersect( cmpBuildable, cmpOrigin, cmpCuboid,
- buildableB->s.modelindex, buildableB->s.origin, buildableB->cuboidSize );
- if( aMatches && !bMatches )
- return -1;
- else if( !aMatches && bMatches )
- return 1;
-
- // If the only spawn is marked, prefer it last
- if( cmpBuildable == BA_A_SPAWN || cmpBuildable == BA_H_SPAWN )
- {
- if( ( buildableA->s.modelindex == BA_A_SPAWN && level.numAlienSpawns == 1 ) ||
- ( buildableA->s.modelindex == BA_H_SPAWN && level.numHumanSpawns == 1 ) )
- return 1;
-
- if( ( buildableB->s.modelindex == BA_A_SPAWN && level.numAlienSpawns == 1 ) ||
- ( buildableB->s.modelindex == BA_H_SPAWN && level.numHumanSpawns == 1 ) )
- return -1;
- }
-
- // If one matches the thing we're building, prefer it
- aMatches = ( buildableA->s.modelindex == cmpBuildable );
- bMatches = ( buildableB->s.modelindex == cmpBuildable );
- if( aMatches && !bMatches )
- return -1;
- else if( !aMatches && bMatches )
- return 1;
-
- // They're the same type
- if( buildableA->s.modelindex == buildableB->s.modelindex )
- {
- gentity_t *powerEntity = G_PowerEntityForPoint( cmpOrigin );
-
- // Prefer the entity that is providing power for this point
- aMatches = ( powerEntity == buildableA );
- bMatches = ( powerEntity == buildableB );
- if( aMatches && !bMatches )
- return -1;
- else if( !aMatches && bMatches )
- return 1;
-
- // Pick the one marked earliest
- return buildableA->deconstructTime - buildableB->deconstructTime;
- }
-
- // Resort to preference list
- for( i = 0; i < sizeof( precedence ) / sizeof( precedence[ 0 ] ); i++ )
- {
- if( buildableA->s.modelindex == precedence[ i ] )
- aPrecedence = i;
-
- if( buildableB->s.modelindex == precedence[ i ] )
- bPrecedence = i;
- }
-
- return aPrecedence - bPrecedence;
-}
-
-/*
-===============
-G_ClearDeconMarks
-
-Remove decon mark from all buildables
-===============
-*/
-void G_ClearDeconMarks( void )
-{
- int i;
- gentity_t *ent;
-
- for( i = MAX_CLIENTS, ent = g_entities + i ; i < level.num_entities ; i++, ent++ )
- {
- if( !ent->inuse )
- continue;
-
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- ent->deconstruct = qfalse;
- }
-}
-
-/*
-===============
-G_FreeMarkedBuildables
-
-Free up build points for a team by deconstructing marked buildables
-===============
-*/
-void G_FreeMarkedBuildables( gentity_t *deconner, char *readable, int rsize,
- char *nums, int nsize )
-{
- int i;
- int bNum;
- int listItems = 0;
- int totalListItems = 0;
- gentity_t *ent;
- int removalCounts[ BA_NUM_BUILDABLES ] = {0};
-
- if( readable && rsize )
- readable[ 0 ] = '\0';
- if( nums && nsize )
- nums[ 0 ] = '\0';
-
- if( !g_markDeconstruct.integer )
- return; // Not enabled, can't deconstruct anything
-
- for( i = 0; i < level.numBuildablesForRemoval; i++ )
- {
- ent = level.markedBuildables[ i ];
- bNum = BG_Buildable( ent->s.modelindex, NULL )->number;
-
- if( removalCounts[ bNum ] == 0 )
- totalListItems++;
-
- G_Damage( ent, NULL, deconner, NULL, NULL, ent->health, 0, MOD_REPLACE );
-
- removalCounts[ bNum ]++;
-
- if( nums )
- Q_strcat( nums, nsize, va( " %d", ent - g_entities ) );
-
- G_FreeEntity( ent );
- }
-
- if( !readable )
- return;
-
- for( i = 0; i < BA_NUM_BUILDABLES; i++ )
- {
- if( removalCounts[ i ] )
- {
- if( listItems )
- {
- if( listItems == ( totalListItems - 1 ) )
- Q_strcat( readable, rsize, va( "%s and ",
- ( totalListItems > 2 ) ? "," : "" ) );
- else
- Q_strcat( readable, rsize, ", " );
- }
- Q_strcat( readable, rsize, va( "%s", BG_Buildable( i, NULL )->humanName ) );
- if( removalCounts[ i ] > 1 )
- Q_strcat( readable, rsize, va( " (%dx)", removalCounts[ i ] ) );
- listItems++;
- }
- }
-}
-
-/*
-===============
G_SufficientBPAvailable
Determine if enough build points can be released for the buildable
and list the buildables that must be destroyed if this is the case
===============
*/
-static itemBuildError_t G_SufficientBPAvailable( buildable_t buildable,
+static itemBuildError_t G_SufficientBPAvailable( gclient_t *builder,
+ buildable_t buildable,
vec3_t origin,
- vec3_t cuboidSize )
+ vec3_t cuboidSize )
{
- int i;
- int numBuildables = 0;
- int numRequired = 0;
- int pointsYielded = 0;
- gentity_t *ent;
- team_t team = BG_Buildable( buildable, NULL )->team;
- int buildPoints = BG_Buildable( buildable, cuboidSize )->buildPoints;
- int remainingBP, remainingSpawns;
- qboolean collision = qfalse;
- int collisionCount = 0;
- qboolean repeaterInRange = qfalse;
- int repeaterInRangeCount = 0;
- itemBuildError_t bpError;
- buildable_t spawn;
- buildable_t core;
- int spawnCount = 0;
- qboolean changed = qtrue;
-
- level.numBuildablesForRemoval = 0;
-
- if( team == TEAM_ALIENS )
- {
- remainingBP = G_GetBuildPoints( origin, team );
- remainingSpawns = level.numAlienSpawns;
- bpError = IBE_NOALIENBP;
- spawn = BA_A_SPAWN;
- core = BA_A_OVERMIND;
- }
- else if( team == TEAM_HUMANS )
- {
- if( buildable == BA_H_REACTOR || buildable == BA_H_REPEATER )
- remainingBP = level.humanBuildPoints;
- else
- remainingBP = G_GetBuildPoints( origin, team );
-
- remainingSpawns = level.numHumanSpawns;
- bpError = IBE_NOHUMANBP;
- spawn = BA_H_SPAWN;
- core = BA_H_REACTOR;
- }
- else
- {
- Com_Error( ERR_FATAL, "team is %d\n", team );
- return IBE_NONE;
- }
-
- // Simple non-marking case
- if( !g_markDeconstruct.integer )
+ int required;
+ int available;
+ int error;
+
+ required = BG_Buildable( buildable, cuboidSize )->buildPoints;
+
+ switch( BG_Buildable( buildable, NULL )->team )
{
- if( remainingBP - buildPoints < 0 )
- return bpError;
-
- // Check for buildable<->buildable collisions
- for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
- {
- if( ent->s.eType != ET_BUILDABLE )
- continue;
-
- if( G_BuildablesIntersect( buildable, origin, cuboidSize, ent->s.modelindex, ent->s.origin, ent->cuboidSize ) )
- return IBE_NOROOM;
-
- }
-
- return IBE_NONE;
+ case TEAM_ALIENS:
+ error = IBE_NOALIENBP;
+ available = G_GetBuildPoints( origin, TEAM_ALIENS );
+ break;
+
+ case TEAM_HUMANS:
+ error = IBE_NOHUMANBP;
+ if( !builder )
+ available = required; //always enough
+ else
+ //first RTG is free
+ if( buildable == BA_H_RTG && !G_IsRTGBuilt() )
+ available = INFINITE;
+ else
+ available = builder->ps.persistant[ PERS_BUILDPOINTS ];
+ break;
}
+
+ if( required > available )
+ return error;
+
+ return IBE_NONE;
- // Set buildPoints to the number extra that are required
- buildPoints -= remainingBP;
- // Build a list of buildable entities
+#if 0
+ // Check for buildable<->buildable collisions
+ // FIXME: is this check even needed?
for( i = MAX_CLIENTS, ent = g_entities + i; i < level.num_entities; i++, ent++ )
{
if( ent->s.eType != ET_BUILDABLE )
continue;
- collision = G_BuildablesIntersect( buildable, origin, cuboidSize, ent->s.modelindex, ent->s.origin, ent->cuboidSize );
-
- 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++;
- }
-
- // Check if this is a repeater and it's in range
- if( buildable == BA_H_REPEATER &&
- buildable == ent->s.modelindex &&
- Distance( ent->s.origin, origin ) < REPEATER_BASESIZE )
- {
- repeaterInRange = qtrue;
- repeaterInRangeCount++;
- }
- else
- repeaterInRange = qfalse;
-
- // Don't allow marked buildables to be replaced in another zone,
- // unless the marked buildable isn't in a zone (and thus unpowered)
- if( team == TEAM_HUMANS &&
- buildable != BA_H_REACTOR &&
- buildable != BA_H_REPEATER &&
- ent->parentNode != G_PowerEntityForPoint( origin ) )
- continue;
-
- if( !ent->inuse )
- continue;
-
- if( ent->health <= 0 )
- continue;
-
- if( ent->buildableTeam != team )
- continue;
-
- // Explicitly disallow replacement of the core buildable with anything
- // other than the core buildable
- if( ent->s.modelindex == core && buildable != core )
- continue;
-
- // Don't allow a power source to be replaced by a dependant
- if( team == TEAM_HUMANS &&
- G_PowerEntityForPoint( origin ) == ent &&
- buildable != BA_H_REPEATER &&
- buildable != core )
- continue;
-
- // Don't include unpowered buildables
- if( !collision && !ent->powered )
- continue;
-
- if( ent->deconstruct )
- {
- level.markedBuildables[ numBuildables++ ] = ent;
-
- // Buildables that are marked here will always end up at the front of the
- // removal list, so just incrementing numBuildablesForRemoval is sufficient
- if( collision || repeaterInRange )
- {
- // Collided with something, so we definitely have to remove it or
- // it's a repeater that intersects the new repeater's power area,
- // so it must be removed
-
- if( collision )
- collisionCount--;
-
- if( repeaterInRange )
- repeaterInRangeCount--;
-
- if( ent->powered )
- pointsYielded += BG_Buildable( ent->s.modelindex, ent->cuboidSize )->buildPoints;
- level.numBuildablesForRemoval++;
- }
- else if( BG_Buildable( ent->s.modelindex, NULL )->uniqueTest &&
- ent->s.modelindex == buildable )
- {
- // If it's a unique buildable, it must be replaced by the same type
- if( ent->powered )
- pointsYielded += BG_Buildable( ent->s.modelindex, ent->cuboidSize )->buildPoints;
- level.numBuildablesForRemoval++;
- }
- }
- }
-
- numRequired = level.numBuildablesForRemoval;
-
- // We still need build points, but have no candidates for removal
- if( buildPoints > 0 && numBuildables == 0 )
- return bpError;
-
- // Collided with something we can't remove
- if( collisionCount > 0 )
- return IBE_NOROOM;
-
- // There are one or more repeaters we can't remove
- if( repeaterInRangeCount > 0 )
- return IBE_RPTPOWERHERE;
-
- // Sort the list
- cmpBuildable = buildable;
- VectorCopy( origin, cmpOrigin );
- VectorCopy( cuboidSize, cmpCuboid );
- qsort( level.markedBuildables, numBuildables, sizeof( level.markedBuildables[ 0 ] ),
- G_CompareBuildablesForRemoval );
-
- // Determine if there are enough markees to yield the required BP
- for( ; pointsYielded < buildPoints && level.numBuildablesForRemoval < numBuildables;
- level.numBuildablesForRemoval++ )
- {
- ent = level.markedBuildables[ level.numBuildablesForRemoval ];
- if( ent->powered )
- pointsYielded += BG_Buildable( ent->s.modelindex, ent->cuboidSize )->buildPoints;
+ if( G_BuildablesIntersect( buildable, origin, cuboidSize, ent->s.modelindex, ent->s.origin, ent->cuboidSize ) )
+ return IBE_NOROOM;
}
-
- // Do another pass to see if we can meet quota with fewer buildables
- // than we have now due to mismatches between priority and BP amounts
- // by repeatedly testing if we can chop off the first thing that isn't
- // required by rules of collision/uniqueness, which are always at the head
- while( changed && level.numBuildablesForRemoval > 1 &&
- level.numBuildablesForRemoval > numRequired )
- {
- int pointsUnYielded = 0;
- changed = qfalse;
- ent = level.markedBuildables[ numRequired ];
- if( ent->powered )
- pointsUnYielded = BG_Buildable( ent->s.modelindex, ent->cuboidSize )->buildPoints;
-
- if( pointsYielded - pointsUnYielded >= buildPoints )
- {
- pointsYielded -= pointsUnYielded;
- memmove( &level.markedBuildables[ numRequired ],
- &level.markedBuildables[ numRequired + 1 ],
- ( level.numBuildablesForRemoval - numRequired )
- * sizeof( gentity_t * ) );
- level.numBuildablesForRemoval--;
- changed = qtrue;
- }
- }
-
- 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( !g_cheats.integer && remainingSpawns > 0 && ( remainingSpawns - spawnCount ) < 1 )
- return IBE_LASTSPAWN;
-
- // Not enough points yielded
- if( pointsYielded < buildPoints )
- return bpError;
- else
- return IBE_NONE;
+#endif
}
/*
@@ -3410,23 +3144,6 @@ static void G_SetBuildableLinkState( qboolean link )
}
}
-static void G_SetBuildableMarkedLinkState( qboolean link )
-{
- int i;
- gentity_t *ent;
-
- for( i = 0; i < level.numBuildablesForRemoval; i++ )
- {
- ent = level.markedBuildables[ i ];
- if( link )
- trap_LinkEntity( ent );
- else
- trap_UnlinkEntity( ent );
- }
-}
-
-
-
/*
================
G_CanBuild
@@ -3482,7 +3199,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
contents = trap_PointContents( entity_origin, -1 );
- if( ( tempReason = G_SufficientBPAvailable( buildable, origin, cuboidSize ) ) != IBE_NONE )
+ if( ( tempReason = G_SufficientBPAvailable( ent->client, buildable, origin, cuboidSize ) ) != IBE_NONE )
reason = tempReason;
if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
@@ -3510,32 +3227,14 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
else if( ent->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
//human criteria
-
- // Check for power
- if( G_IsPowered( entity_origin ) == BA_NONE )
- {
- //tell player to build a repeater to provide power
- if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER )
- reason = IBE_NOPOWERHERE;
- }
+ if( !G_PowerForPoint( origin ) &&
+ buildable != BA_H_RTG )
+ reason = IBE_NOPOWERHERE;
//this buildable requires a DCC
if( BG_Buildable( buildable, NULL )->dccTest && !G_IsDCCBuilt( ) )
reason = IBE_NODCC;
- //check that there is a parent reactor when building a repeater
- if( buildable == BA_H_REPEATER )
- {
- tempent = G_Reactor( );
-
- if( tempent == NULL ) // No reactor
- reason = IBE_RPTNOREAC;
- else if( g_markDeconstruct.integer && G_IsPowered( entity_origin ) == BA_H_REACTOR )
- reason = IBE_RPTPOWERHERE;
- else if( !g_markDeconstruct.integer && G_IsPowered( entity_origin ) )
- reason = IBE_RPTPOWERHERE;
- }
-
// Check permission to build here
if( tr1.surfaceFlags & SURF_NOHUMANBUILD || contents & CONTENTS_NOHUMANBUILD )
reason = IBE_PERMISSION;
@@ -3549,7 +3248,7 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
if( BG_Buildable( buildable, NULL )->uniqueTest )
{
tempent = G_FindBuildable( buildable );
- if( tempent && !tempent->deconstruct )
+ if( tempent )
{
switch( buildable )
{
@@ -3570,18 +3269,12 @@ itemBuildError_t G_CanBuild( gentity_t *ent, buildable_t buildable, int distance
//check there is enough room to spawn from (presuming this is a spawn)
if( reason == IBE_NONE )
- {
- G_SetBuildableMarkedLinkState( qfalse );
if( G_CheckSpawnPoint( ENTITYNUM_NONE, origin, normal, buildable, NULL ) != NULL )
reason = IBE_NORMAL;
- G_SetBuildableMarkedLinkState( qtrue );
- }
//this item does not fit here
if( reason == IBE_NONE && ( tr2.startsolid || !COMPARE_FLOAT_EPSILON(tr3.fraction,1.0f) ) )
reason = IBE_NOROOM;
- if( reason != IBE_NONE )
- level.numBuildablesForRemoval = 0;
if( g_buildableDensityLimit.integer > 0 )
{
@@ -3661,12 +3354,11 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
{
gentity_t *built;
vec3_t localOrigin;
- char readable[ MAX_STRING_CHARS ];
char buildnums[ MAX_STRING_CHARS ];
buildLog_t *log;
qboolean cuboid;
- cuboid=BG_Buildable(buildable,NULL)->cuboid;
+ cuboid = BG_Buildable(buildable,NULL)->cuboid;
VectorCopy( origin, localOrigin );
@@ -3675,10 +3367,6 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
else
log = NULL;
- // Free existing buildables
- G_FreeMarkedBuildables( builder, readable, sizeof( readable ),
- buildnums, sizeof( buildnums ) );
-
// Spawn the buildable
built = G_Spawn();
built->s.eType = ET_BUILDABLE;
@@ -3692,13 +3380,13 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
if( !builder->client )
VectorMA( localOrigin, 1.0f, normal, localOrigin );
- if(cuboid)
+ if( cuboid )
{
- BG_CuboidBBox(cuboidSize,built->r.mins,built->r.maxs);
- VectorCopy(cuboidSize,&built->cuboidSize);
+ BG_CuboidBBox( cuboidSize, built->r.mins, built->r.maxs );
+ VectorCopy( cuboidSize, &built->cuboidSize );
}
else
- BG_BuildableBoundingBox(buildable,built->r.mins,built->r.maxs);
+ BG_BuildableBoundingBox( buildable, built->r.mins, built->r.maxs );
built->health = 1;
built->healthLeft = BG_Buildable( buildable, cuboidSize )->health-1;
@@ -3713,8 +3401,7 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
built->spawned = qfalse;
built->buildTime = built->s.time = level.time;
- // build instantly in cheat mode
- if( builder->client && (g_cheats.integer || g_instantBuild.integer) )
+ if( builder->client && g_instantBuild.integer )
{
built->health = BG_Buildable( buildable, cuboidSize )->health;
built->buildTime = built->s.time =
@@ -3804,16 +3491,34 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
case BA_H_REACTOR:
built->think = HReactor_Think;
built->die = HSpawn_Die;
- built->use = HRepeater_Use;
+ built->use = HSwitchable_Use;
built->powered = built->active = qtrue;
break;
case BA_H_REPEATER:
built->think = HRepeater_Think;
built->die = HRepeater_Die;
- built->use = HRepeater_Use;
+ built->use = HSwitchable_Use;
built->count = -1;
break;
+
+ case BA_H_CAPBANK:
+ built->think = HCapbank_Think;
+ built->die = HSpawn_Die;
+ built->use = HSwitchable_Use;
+ break;
+
+ case BA_H_RTG:
+ built->think = HRTG_Think;
+ built->die = HSpawn_Die;
+ built->use = HSwitchable_Use;
+ break;
+
+ case BA_H_REFINERY:
+ built->think = HRefinery_Think;
+ built->die = HSpawn_Die;
+ //built->use = HSwitchable_Use;
+ break;
default:
//erk
@@ -3839,15 +3544,14 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
G_SetOrigin( built, localOrigin );
- // roughly nudge the buildable onto the surface D:<
VectorScale( normal, -512.0f, built->s.pos.trDelta );
- if(BG_Buildable(buildable, NULL)->cuboid)
- VectorCopy(cuboidSize,built->s.angles);
+ if( BG_Buildable( buildable, NULL )->cuboid )
+ VectorCopy( cuboidSize,built->s.angles );
else
{
- VectorCopy( angles, built->s.angles );
- built->s.angles[ PITCH ] = 0.0f;
+ VectorCopy( angles, built->s.angles );
+ built->s.angles[ PITCH ] = 0.0f;
}
built->s.pos.trType = BG_Buildable( buildable, NULL )->traj;
@@ -3859,13 +3563,8 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
built->s.angles2[ YAW ] = angles[ YAW ];
built->s.angles2[ PITCH ] = MGTURRET_VERTICALCAP;
- if( BG_Buildable( buildable, NULL )->team == TEAM_ALIENS )
- {
- built->powered = qtrue;
- built->s.eFlags |= EF_B_POWERED;
- }
- else if( ( built->powered = G_FindPower( built, qfalse ) ) )
- built->s.eFlags |= EF_B_POWERED;
+ built->powered = qtrue;
+ built->s.eFlags |= EF_B_POWERED;
built->s.eFlags &= ~EF_B_SPAWNED;
@@ -3878,32 +3577,47 @@ static gentity_t *G_Build( gentity_t *builder, buildable_t buildable,
if( built->builtBy >= 0 )
G_SetBuildableAnim( built, BANIM_CONSTRUCT1, qtrue );
+ if( BG_Buildable( buildable, NULL )->team == TEAM_HUMANS )
+ {
+ //special case for the RTG unit that can be built w/o power
+ if( buildable == BA_H_RTG )
+ built->requiresPower = qfalse;
+ else
+ built->requiresPower = qtrue;
+
+ built->isPowerSource = qfalse;
+ built->resistance = PREBUILD_RESISTANCE;
+ if( BG_Buildable( buildable, NULL )->isPowerSource ||
+ buildable == BA_H_REPEATER )
+ built->active = qtrue; //spawn enabled
+ }
+
+ // subtract build points
+ if( buildable != BA_H_RTG || G_IsRTGBuilt( ) ) //first RTG is free
+ if( builder && builder->client )
+ builder->client->ps.persistant[ PERS_BUILDPOINTS ] -= BG_Buildable( buildable, cuboidSize )->buildPoints;
+
+ BG_CuboidPackHealthSafe( built->s.modelindex, &built->s, built->health );
+
trap_LinkEntity( built );
if( builder && builder->client )
{
G_TeamCommand( builder->client->ps.stats[ STAT_TEAM ],
- va( "print \"%s ^2built^7 by %s%s%s\n\"",
- G_CuboidName(built->s.modelindex,cuboidSize,qfalse),
- builder->client->pers.netname,
- ( readable[ 0 ] ) ? "^7, ^3replacing^7 " : "",
- readable ) );
- G_LogPrintf( "Construct: %d %d %s%s: %s" S_COLOR_WHITE " is building "
- "%s%s%s\n",
+ va( "print \"%s ^2built^7 by %s\n\"",
+ G_CuboidName( built->s.modelindex, cuboidSize, qfalse ),
+ builder->client->pers.netname ) );
+ G_LogPrintf( "Construct: %d %d %s%s: %s" S_COLOR_WHITE " is building %s\n",
builder - g_entities,
built - g_entities,
BG_Buildable( built->s.modelindex, NULL )->name,
buildnums,
builder->client->pers.netname,
- G_CuboidName(built->s.modelindex,built->cuboidSize,qtrue),
- readable[ 0 ] ? ", replacing " : "",
- readable );
+ G_CuboidName( built->s.modelindex, built->cuboidSize, qtrue ) );
}
if( log )
G_BuildLogSet( log, built );
-
- BG_CuboidPackHealthSafe(built->s.modelindex,&built->s,built->health);
return built;
}
@@ -4026,6 +3740,8 @@ static gentity_t *G_FinishSpawningBuildable( gentity_t *ent, qboolean force )
built->health = BG_Buildable( buildable, built->cuboidSize )->health;
built->s.eFlags |= EF_B_SPAWNED;
+ G_SetupPowerEntity( built );
+
// drop towards normal surface
VectorScale( built->s.origin2, -4096.0f, dest );
VectorAdd( dest, built->s.origin, dest );
@@ -4407,8 +4123,6 @@ buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate )
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 );
@@ -4464,8 +4178,6 @@ void G_BuildLogRevertThink( gentity_t *ent )
}
built = G_FinishSpawningBuildable( ent, qtrue );
- if( ( built->deconstruct = ent->deconstruct ) )
- built->deconstructTime = ent->deconstructTime;
built->buildTime = built->s.time = 0;
G_KillBox( built );
@@ -4482,8 +4194,6 @@ void G_BuildLogRevert( int id )
int i;
vec3_t dist;
- level.numBuildablesForRemoval = 0;
-
level.numBuildLogs -= level.buildId - id;
while( level.buildId > id )
{
@@ -4521,8 +4231,6 @@ void G_BuildLogRevert( int id )
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;
@@ -4539,27 +4247,6 @@ void G_BuildLogRevert( int id )
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 );
- }
- }
- }
}
}
}
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 7596ea1..a3c7a67 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1482,6 +1482,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
for( i = 0; i < MAX_PERSISTANT; i++ )
persistant[ i ] = client->ps.persistant[ i ];
+ persistant[ PERS_BUILDPOINTS ] = 0; // clear buildpoints
eventSequence = client->ps.eventSequence;
memset( client, 0, sizeof( *client ) );
@@ -1795,11 +1796,12 @@ void ClientDisconnect( int clientNum )
G_RelayCuboidToSpectators
Called everytime a player changes his cuboid size.
-A server command is issued to everyone spectating him
-so that their clients can know the cuboid size as well.
============
*/
-void G_RelayCuboidToSpectators(gentity_t *self)
+void G_RelayCuboidToSpectators( gentity_t *self )
{
+ self->client->ps.misc[ MISC_CUBOID_X ] = self->client->cuboidSelection[ 0 ] * 10;
+ self->client->ps.misc[ MISC_CUBOID_Y ] = self->client->cuboidSelection[ 1 ] * 10;
+ self->client->ps.misc[ MISC_CUBOID_Z ] = self->client->cuboidSelection[ 2 ] * 10;
}
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 2c15638..c1da4e0 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -1363,7 +1363,7 @@ void Cmd_CallVote_f( gentity_t *ent )
}
else if( !Q_stricmp( vote, "map_restart" ) )
{
- if( level.time / 60000 >= g_restartVoteTimelimit.integer )
+ if( g_restartVoteTimelimit.integer && ( level.time - level.startTime ) / 60000 >= g_restartVoteTimelimit.integer )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s: It's not allowed to call a restart vote after %i minute%s.\n\"",
@@ -1377,7 +1377,7 @@ void Cmd_CallVote_f( gentity_t *ent )
}
else if( !Q_stricmp( vote, "map" ) )
{
- if( level.time / 60000 >= g_mapVoteTimelimit.integer )
+ if( g_mapVoteTimelimit.integer && ( level.time - level.startTime ) / 60000 >= g_mapVoteTimelimit.integer )
{
trap_SendServerCommand( ent-g_entities,
va( "print \"%s: It's not allowed to call a map vote after %i minute%s. Call a ^1nextmap^7 vote instead\n\"",
@@ -1434,7 +1434,7 @@ void Cmd_CallVote_f( gentity_t *ent )
}
else if( !Q_stricmp( vote, "sudden_death" ) )
{
- if(!g_suddenDeathVotePercent.integer)
+ if( !g_suddenDeathVotePercent.integer )
{
trap_SendServerCommand( ent-g_entities,
"print \"Sudden Death votes have been disabled\n\"" );
@@ -1918,6 +1918,7 @@ void Cmd_Destroy_f( gentity_t *ent )
char cmd[ 12 ];
qboolean deconstruct = qtrue;
qboolean lastSpawn = qfalse;
+ int bp;
if( ent->client->pers.namelog->denyBuild )
{
@@ -1942,22 +1943,21 @@ void Cmd_Destroy_f( gentity_t *ent )
( ( ent->client->ps.weapon >= WP_ABUILD ) &&
( ent->client->ps.weapon <= WP_HBUILD ) ) )
{
+ //give some BP back: 20% for a dead buildable, 80% for a new one
+ bp = BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->buildPoints;
+ bp *= MAX( (float)traceEnt->health, 0.0f ) /
+ BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->health * 0.6f + 0.2f;
+
// Always let the builder prevent the explosion
if( traceEnt->health <= 0 )
{
+ ent->client->ps.persistant[ PERS_BUILDPOINTS ] += bp;
G_QueueBuildPoints( traceEnt );
G_RewardAttackers( traceEnt );
G_FreeEntity( traceEnt );
return;
}
- // Cancel deconstruction (unmark)
- if( deconstruct && g_markDeconstruct.integer && traceEnt->deconstruct )
- {
- traceEnt->deconstruct = qfalse;
- return;
- }
-
// Prevent destruction of the last spawn
if( ent->client->pers.teamSelection == TEAM_ALIENS &&
traceEnt->s.modelindex == BA_A_SPAWN )
@@ -1972,8 +1972,7 @@ void Cmd_Destroy_f( gentity_t *ent )
lastSpawn = qtrue;
}
- if( lastSpawn && !g_cheats.integer &&
- !g_markDeconstruct.integer )
+ if( lastSpawn && !g_cheats.integer )
{
G_TriggerMenu( ent->client->ps.clientNum, MN_B_LASTSPAWN );
return;
@@ -1986,9 +1985,7 @@ void Cmd_Destroy_f( gentity_t *ent )
return;
}
- if( !g_markDeconstruct.integer ||
- ( ent->client->pers.teamSelection == TEAM_HUMANS &&
- !G_FindPower( traceEnt, qtrue ) ) )
+ if( ent->client->pers.teamSelection == TEAM_HUMANS )
{
if( ent->client->buildTimer )
{
@@ -2004,21 +2001,18 @@ void Cmd_Destroy_f( gentity_t *ent )
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
traceEnt->health, 0, MOD_SUICIDE );
}
- else if( g_markDeconstruct.integer &&
- ( ent->client->pers.teamSelection != TEAM_HUMANS ||
- G_FindPower( traceEnt , qtrue ) || lastSpawn ) )
- {
- traceEnt->deconstruct = qtrue; // Mark buildable for deconstruction
- traceEnt->deconstructTime = level.time;
- }
else
{
if( !g_cheats.integer && !g_instantBuild.integer ) // add a bit to the build timer
{
- ent->client->buildTimer +=
- BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->buildTime / 4;
- G_RecalcBuildTimer(ent->client);
+ ent->client->buildTimer += BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->buildTime / 4;
+ G_RecalcBuildTimer(ent->client);
}
+
+ ent->client->ps.persistant[ PERS_BUILDPOINTS ] += bp;
+ if( ent->client->ps.persistant[ PERS_BUILDPOINTS ] > CKIT_STORAGE )
+ ent->client->ps.persistant[ PERS_BUILDPOINTS ] = CKIT_STORAGE;
+
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
traceEnt->health, 0, MOD_DECONSTRUCT );
G_FreeEntity( traceEnt );
@@ -2782,6 +2776,69 @@ void Cmd_Reload_f( gentity_t *ent )
playerState_t *ps = &ent->client->ps;
int ammo;
+ // reload transfers mass in case of CKit
+ if( ps->weapon == WP_HBUILD )
+ {
+ trace_t trace;
+ vec3_t eyes, view, point;
+ gentity_t *other;
+
+ #define USE_OBJECT_RANGE 100
+
+ // look for object infront of player
+ AngleVectors( ent->client->ps.viewangles, view, NULL, NULL );
+ BG_GetClientViewOrigin( &ent->client->ps, eyes );
+ VectorMA( eyes, USE_OBJECT_RANGE, view, point );
+
+ trap_Trace( &trace, ent->client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT );
+ other = &g_entities[ trace.entityNum ];
+
+ // transfer FROM buildable
+ if( other->s.eType == ET_BUILDABLE )
+ {
+ if( other->buildableTeam == TEAM_HUMANS &&
+ BG_Buildable( other->s.modelindex, NULL )->hasStorage &&
+ other->spawned && other->health >= 0 &&
+ other->storedBP > 0 )
+ {
+ float bp;
+
+ bp = floor( MIN( MIN( other->storedBP, 4 ),
+ CKIT_STORAGE - ent->client->ps.persistant[ PERS_BUILDPOINTS ] ) );
+
+ other->storedBP -= bp;
+ ent->client->ps.persistant[ PERS_BUILDPOINTS ] += bp;
+
+ if( bp )
+ G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );
+ else
+ G_AddEvent( ent, EV_BUILD_REPAIRED, 0 );
+ }
+ }
+ //transfer TO another player
+ else if( other->client )
+ {
+ if( BG_GetPlayerWeapon( &other->client->ps ) == WP_HBUILD &&
+ other->client->ps.stats[ STAT_HEALTH ] >= 0 )
+ {
+ int bp;
+
+ bp = MIN( MIN( ent->client->ps.persistant[ PERS_BUILDPOINTS ], 4 ),
+ CKIT_STORAGE - other->client->ps.persistant[ PERS_BUILDPOINTS ] );
+
+ ent->client->ps.persistant[ PERS_BUILDPOINTS ] -= bp;
+ other->client->ps.persistant[ PERS_BUILDPOINTS ] += bp;
+
+ if( bp )
+ G_AddEvent( ent, EV_RPTUSE_SOUND, 0 );
+ else
+ G_AddEvent( ent, EV_BUILD_REPAIRED, 0 );
+ }
+ }
+
+ return;
+ }
+
// weapon doesn't ever need reloading
if( BG_Weapon( ps->weapon )->infiniteAmmo )
return;
@@ -3305,7 +3362,6 @@ Cmd_Debug1_f
*/
void Cmd_Debug1_f( gentity_t *other )
{
- other->client->ps.stats[ STAT_SHAKE ] += 70;
}
/*
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index fe5d607..6acf6b7 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -195,17 +195,18 @@ float G_RewardAttackers( gentity_t *self )
AddScore( player, stageValue );
- // killing buildables earns score, but not credits
- if( self->s.eType != ET_BUILDABLE )
- {
- G_AddCreditToClient( player->client, stageValue, qtrue );
+ if( self->s.eType == ET_BUILDABLE )
+ stageValue *= g_buildableValueModifier.value;
+ else
+ stageValue *= g_playerValueModifier.value;
+
+ G_AddCreditToClient( player->client, stageValue, qtrue );
- // add to stage counters
- if( player->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
- alienCredits += stageValue;
- else if( player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
- humanCredits += stageValue;
- }
+ // add to stage counters
+ if( player->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS )
+ alienCredits += stageValue;
+ else if( player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
+ humanCredits += stageValue;
}
self->credits[ i ] = 0;
}
@@ -1069,7 +1070,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
// base is under attack warning if DCC'd
- if( targ->buildableTeam == TEAM_HUMANS && G_FindDCC( targ ) &&
+ if( targ->buildableTeam == TEAM_HUMANS && G_IsDCCBuilt( ) &&
level.time > level.humanBaseAttackTimer )
{
level.humanBaseAttackTimer = level.time + DC_ATTACK_PERIOD;
@@ -1085,7 +1086,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
// add to the attacker's hit counter
if( attacker->client && targ != attacker && targ->health > 0
&& targ->s.eType != ET_MISSILE
- && targ->s.eType != ET_GENERAL )
+ && targ->s.eType != ET_GENERAL
+ && mod != MOD_DECONSTRUCT )
{
if( OnSameTeam( targ, attacker ) )
attacker->client->ps.persistant[ PERS_HITS ]--;
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 001c7d9..944140f 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -198,16 +198,12 @@ struct gentity_s
gentity_t *parentNode; // for creep and defence/spawn dependencies
qboolean active; // for power repeater, but could be useful elsewhere
qboolean locked; // used for turret tracking
- qboolean powered; // for human buildables
int builtBy; // clientNum of person that built this
- int dcc; // number of controlling dccs
qboolean spawned; // whether or not this buildable has finished spawning
int shrunkTime; // time when a barricade shrunk or zero
int buildTime; // when this buildable was built
int animTime; // last animation change
int time1000; // timer evaluated every second
- qboolean deconstruct; // deconstruct if no BP left
- int deconstructTime; // time at which structure marked
int overmindAttackTimer;
int overmindDyingTimer;
int overmindSpawnsTimer;
@@ -243,10 +239,24 @@ struct gentity_s
qboolean pointAgainstWorld; // don't use the bbox for map collisions
- int buildPointZone; // index for zone
- int usesBuildPointZone; // does it use a zone?
+ vec3_t cuboidSize;
- vec3_t cuboidSize;
+ //power grid
+ qboolean requiresPower; // false for telenodes, cuboids, etc.
+ qboolean isPowerSource; // true for all active elements (including the capbank)
+
+ int powerNetwork; // which network is it in (0 is no network)
+ qboolean powered; // is this buildable powered?
+ qboolean surge; // true if the buildable requests high amount of power (resistance=surgeResistance)
+ // IMPORTANT NOTE: it should NOT depend on anything power-related to avoid
+ // unstable network states
+ qboolean surgePowered; // is surge powered?
+ float voltage; // voltage drop (load) or gain (source)
+ float current; // current flow
+ float resistance; // resistance (for sources it's their internal resistance)
+
+ //mass
+ float storedBP;
};
typedef enum
@@ -485,16 +495,6 @@ void G_PrintSpawnQueue( spawnQueue_t *sq );
#define MAX_DAMAGE_REGION_TEXT 8192
#define MAX_DAMAGE_REGIONS 16
-// build point zone
-typedef struct
-{
- int active;
-
- int totalBuildPoints;
- int queuedBuildPoints;
- int nextQueueTime;
-} buildPointZone_t;
-
// store locational damage regions
typedef struct damageRegion_s
{
@@ -641,14 +641,6 @@ typedef struct
int alienBuildPoints;
int alienBuildPointQueue;
int alienNextQueueTime;
- int humanBuildPoints;
- int humanBuildPointQueue;
- int humanNextQueueTime;
-
- buildPointZone_t *buildPointZones;
-
- gentity_t *markedBuildables[ MAX_GENTITIES ];
- int numBuildablesForRemoval;
int alienKills;
int humanKills;
@@ -801,8 +793,8 @@ gentity_t *G_CheckSpawnPoint( int spawnNum, const vec3_t origin,
buildable_t G_IsPowered( vec3_t origin );
qboolean G_IsDCCBuilt( void );
-int G_FindDCC( gentity_t *self );
-gentity_t *G_Reactor( void );
+qboolean G_IsRTGBuilt( void );
+qboolean G_FindDCC( gentity_t *self );
gentity_t *G_Overmind( void );
qboolean G_FindCreep( gentity_t *self );
@@ -823,12 +815,7 @@ void G_BaseSelfDestruct( team_t team );
int G_NextQueueTime( int queuedBP, int totalBP, int queueBaseRate );
void G_QueueBuildPoints( gentity_t *self );
int G_GetBuildPoints( const vec3_t pos, team_t team );
-int G_GetMarkedBuildPoints( const vec3_t pos, team_t team );
qboolean G_FindPower( gentity_t *self, qboolean searchUnspawned );
-gentity_t *G_PowerEntityForPoint( const vec3_t origin );
-gentity_t *G_PowerEntityForEntity( gentity_t *ent );
-gentity_t *G_RepeaterEntityForPoint( vec3_t origin );
-gentity_t *G_InPowerZone( gentity_t *self );
buildLog_t *G_BuildLogNew( gentity_t *actor, buildFate_t fate );
void G_BuildLogSet( buildLog_t *log, gentity_t *ent );
void G_BuildLogAuto( gentity_t *actor, gentity_t *buildable, buildFate_t fate );
@@ -836,6 +823,7 @@ void G_BuildLogRevert( int id );
const char *G_CuboidName(buildable_t buildable, const vec3_t cuboidSize, qboolean verbose);
void G_LayoutBuildItem( buildable_t buildable, vec3_t origin, vec3_t angles, vec3_t origin2, vec3_t angles2 );
void G_RemoveUnbuiltBuildables( gentity_t *self );
+void G_UpdatePowerGrid( float dt );
//
// g_utils.c
@@ -1158,11 +1146,6 @@ extern vmCvar_t pmove_msec;
extern vmCvar_t g_alienBuildPoints;
extern vmCvar_t g_alienBuildQueueTime;
-extern vmCvar_t g_humanBuildPoints;
-extern vmCvar_t g_humanBuildQueueTime;
-extern vmCvar_t g_humanRepeaterBuildPoints;
-extern vmCvar_t g_humanRepeaterBuildQueueTime;
-extern vmCvar_t g_humanRepeaterMaxZones;
extern vmCvar_t g_humanStage;
extern vmCvar_t g_humanCredits;
extern vmCvar_t g_humanMaxStage;
@@ -1182,8 +1165,6 @@ extern vmCvar_t g_disabledEquipment;
extern vmCvar_t g_disabledClasses;
extern vmCvar_t g_disabledBuildables;
-extern vmCvar_t g_markDeconstruct;
-
extern vmCvar_t g_debugMapRotation;
extern vmCvar_t g_currentMapRotation;
extern vmCvar_t g_mapRotationNodes;
@@ -1227,6 +1208,11 @@ extern vmCvar_t g_cuboidHealthLimit;
extern vmCvar_t g_buildableDensityLimit;
extern vmCvar_t g_buildableDensityLimitRange;
+extern vmCvar_t g_buildableValueModifier;
+extern vmCvar_t g_playerValueModifier;
+extern vmCvar_t g_massYieldModifier;
+extern vmCvar_t g_voltageModifier;
+
void trap_Print( const char *fmt );
void trap_Error( const char *fmt );
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 0f9c31c..1cbf897 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -86,11 +86,6 @@ vmCvar_t g_maxNameChanges;
vmCvar_t g_alienBuildPoints;
vmCvar_t g_alienBuildQueueTime;
-vmCvar_t g_humanBuildPoints;
-vmCvar_t g_humanBuildQueueTime;
-vmCvar_t g_humanRepeaterBuildPoints;
-vmCvar_t g_humanRepeaterBuildQueueTime;
-vmCvar_t g_humanRepeaterMaxZones;
vmCvar_t g_humanStage;
vmCvar_t g_humanCredits;
vmCvar_t g_humanMaxStage;
@@ -110,8 +105,6 @@ vmCvar_t g_disabledEquipment;
vmCvar_t g_disabledClasses;
vmCvar_t g_disabledBuildables;
-vmCvar_t g_markDeconstruct;
-
vmCvar_t g_debugMapRotation;
vmCvar_t g_currentMapRotation;
vmCvar_t g_mapRotationNodes;
@@ -158,6 +151,11 @@ vmCvar_t g_cuboidMode;
vmCvar_t g_buildableDensityLimit;
vmCvar_t g_buildableDensityLimitRange;
+vmCvar_t g_buildableValueModifier;
+vmCvar_t g_playerValueModifier;
+vmCvar_t g_massYieldModifier;
+vmCvar_t g_voltageModifier;
+
// copy cvars that can be set in worldspawn so they can be restored later
static char cv_gravity[ MAX_CVAR_VALUE_STRING ];
static char cv_humanMaxStage[ MAX_CVAR_VALUE_STRING ];
@@ -232,11 +230,6 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_alienBuildPoints, "g_alienBuildPoints", DEFAULT_ALIEN_BUILDPOINTS, 0, 0, qfalse },
{ &g_alienBuildQueueTime, "g_alienBuildQueueTime", DEFAULT_ALIEN_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
- { &g_humanBuildPoints, "g_humanBuildPoints", DEFAULT_HUMAN_BUILDPOINTS, 0, 0, qfalse },
- { &g_humanBuildQueueTime, "g_humanBuildQueueTime", DEFAULT_HUMAN_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
- { &g_humanRepeaterBuildPoints, "g_humanRepeaterBuildPoints", DEFAULT_HUMAN_REPEATER_BUILDPOINTS, CVAR_ARCHIVE, 0, qfalse },
- { &g_humanRepeaterMaxZones, "g_humanRepeaterMaxZones", DEFAULT_HUMAN_REPEATER_MAX_ZONES, CVAR_ARCHIVE, 0, qfalse },
- { &g_humanRepeaterBuildQueueTime, "g_humanRepeaterBuildQueueTime", DEFAULT_HUMAN_REPEATER_QUEUE_TIME, CVAR_ARCHIVE, 0, qfalse },
{ &g_humanStage, "g_humanStage", "0", 0, 0, qfalse },
{ &g_humanCredits, "g_humanCredits", "0", 0, 0, qfalse },
{ &g_humanMaxStage, "g_humanMaxStage", DEFAULT_HUMAN_MAX_STAGE, 0, 0, qfalse, cv_humanMaxStage },
@@ -261,8 +254,6 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_floodMaxDemerits, "g_floodMaxDemerits", "5000", CVAR_ARCHIVE, 0, qfalse },
{ &g_floodMinTime, "g_floodMinTime", "2000", CVAR_ARCHIVE, 0, qfalse },
- { &g_markDeconstruct, "g_markDeconstruct", "3", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },
-
{ &g_debugMapRotation, "g_debugMapRotation", "0", 0, 0, qfalse },
{ &g_currentMapRotation, "g_currentMapRotation", "-1", 0, 0, qfalse }, // -1 = NOT_ROTATING
{ &g_mapRotationNodes, "g_mapRotationNodes", "", CVAR_ROM, 0, qfalse },
@@ -301,7 +292,12 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_cuboidMode, "g_cuboidMode", "0", CVAR_ARCHIVE, 0, qfalse },
{ &g_buildableDensityLimit, "g_buildableDensityLimit", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
- { &g_buildableDensityLimitRange, "g_buildableDensityLimitRange", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse }
+ { &g_buildableDensityLimitRange, "g_buildableDensityLimitRange", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
+
+ { &g_playerValueModifier, "g_playerValueModifier", "0.5", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
+ { &g_buildableValueModifier, "g_buildableValueModifier", "0.16", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
+ { &g_massYieldModifier, "g_massYieldModifier", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
+ { &g_voltageModifier, "g_voltageModifier", "1.0", CVAR_ARCHIVE | CVAR_SERVERINFO }
};
static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] );
@@ -1197,7 +1193,6 @@ void G_CalculateBuildPoints( void )
{
int i;
buildable_t buildable;
- buildPointZone_t *zone;
// BP queue updates
while( level.alienBuildPointQueue > 0 &&
@@ -1209,15 +1204,6 @@ void G_CalculateBuildPoints( void )
g_alienBuildQueueTime.integer );
}
- while( level.humanBuildPointQueue > 0 &&
- level.humanNextQueueTime < level.time )
- {
- level.humanBuildPointQueue--;
- level.humanNextQueueTime += G_NextQueueTime( level.humanBuildPointQueue,
- g_humanBuildPoints.integer,
- g_humanBuildQueueTime.integer );
- }
-
// Sudden Death checks
if( G_TimeTilSuddenDeath( ) <= 0 && level.suddenDeathWarning < TW_PASSED )
{
@@ -1226,7 +1212,6 @@ void G_CalculateBuildPoints( void )
trap_SendServerCommand( -1, "print \"Beginning Sudden Death.\n\"" );
trap_SendServerCommand( -1, "announce suddendeath" );
level.suddenDeathWarning = TW_PASSED;
- G_ClearDeconMarks( );
// Clear blueprints, or else structs that cost 0 BP can still be built after SD
for( i = 0; i < level.maxclients; i++ )
@@ -1246,101 +1231,26 @@ void G_CalculateBuildPoints( void )
level.suddenDeathWarning = TW_IMMINENT;
}
- level.humanBuildPoints = g_humanBuildPoints.integer - level.humanBuildPointQueue;
level.alienBuildPoints = g_alienBuildPoints.integer - level.alienBuildPointQueue;
- // Reset buildPointZones
- for( i = 0; i < g_humanRepeaterMaxZones.integer; i++ )
- {
- buildPointZone_t *zone = &level.buildPointZones[ i ];
-
- zone->active = qfalse;
- zone->totalBuildPoints = g_humanRepeaterBuildPoints.integer;
- }
-
// Iterate through entities
for( i = MAX_CLIENTS; i < level.num_entities; i++ )
{
gentity_t *ent = &g_entities[ i ];
- buildPointZone_t *zone;
buildable_t buildable;
int cost;
if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD )
continue;
- // mark a zone as active
- if( ent->usesBuildPointZone )
- {
- assert( ent->buildPointZone >= 0 && ent->buildPointZone < g_humanRepeaterMaxZones.integer );
-
- zone = &level.buildPointZones[ ent->buildPointZone ];
- zone->active = qtrue;
- }
-
// Subtract the BP from the appropriate pool
buildable = ent->s.modelindex;
cost = BG_Buildable( buildable, ent->cuboidSize )->buildPoints;
if( ent->buildableTeam == TEAM_ALIENS )
level.alienBuildPoints -= cost;
- if( buildable == BA_H_REPEATER )
- level.humanBuildPoints -= cost;
- else if( buildable != BA_H_REACTOR )
- {
- gentity_t *power = G_PowerEntityForEntity( ent );
-
- if( power )
- {
- if( power->s.modelindex == BA_H_REACTOR )
- level.humanBuildPoints -= cost;
- else if( power->s.modelindex == BA_H_REPEATER && power->usesBuildPointZone )
- level.buildPointZones[ power->buildPointZone ].totalBuildPoints -= cost;
- }
- }
}
- // Finally, update repeater zones and their queues
- // note that this has to be done after the used BP is calculated
- for( i = MAX_CLIENTS; i < level.num_entities; i++ )
- {
- gentity_t *ent = &g_entities[ i ];
-
- if( ent->s.eType != ET_BUILDABLE || ent->s.eFlags & EF_DEAD ||
- ent->buildableTeam != TEAM_HUMANS )
- continue;
-
- buildable = ent->s.modelindex;
-
- if( buildable != BA_H_REPEATER )
- continue;
-
- if( ent->usesBuildPointZone && level.buildPointZones[ ent->buildPointZone ].active )
- {
- zone = &level.buildPointZones[ ent->buildPointZone ];
-
- if( G_TimeTilSuddenDeath( ) > 0 )
- {
- // BP queue updates
- while( zone->queuedBuildPoints > 0 &&
- zone->nextQueueTime < level.time )
- {
- zone->queuedBuildPoints--;
- zone->nextQueueTime += G_NextQueueTime( zone->queuedBuildPoints,
- zone->totalBuildPoints,
- g_humanRepeaterBuildQueueTime.integer );
- }
- }
- else
- {
- zone->totalBuildPoints = zone->queuedBuildPoints = 0;
- }
- }
- }
-
- if( level.humanBuildPoints < 0 )
- level.humanBuildPoints = 0;
-
if( level.alienBuildPoints < 0 )
level.alienBuildPoints = 0;
}
@@ -2338,14 +2248,6 @@ void CheckCvars( void )
trap_Cvar_Set( "g_needpass", "0" );
}
- // Unmark any structures for deconstruction when
- // the server setting is changed
- if( g_markDeconstruct.modificationCount != lastMarkDeconModCount )
- {
- lastMarkDeconModCount = g_markDeconstruct.modificationCount;
- G_ClearDeconMarks( );
- }
-
// If we change g_suddenDeathTime during a map, we need to update
// when sd will begin
if( g_suddenDeathTime.modificationCount != lastSDTimeModCount )
@@ -2354,24 +2256,6 @@ void CheckCvars( void )
level.suddenDeathBeginTime = g_suddenDeathTime.integer * 60000;
}
- // If the number of zones changes, we need a new array
- if( g_humanRepeaterMaxZones.integer != lastNumZones )
- {
- buildPointZone_t *newZones;
- size_t newsize = g_humanRepeaterMaxZones.integer * sizeof( buildPointZone_t );
- size_t oldsize = lastNumZones * sizeof( buildPointZone_t );
-
- newZones = BG_Alloc( newsize );
- if( level.buildPointZones )
- {
- Com_Memcpy( newZones, level.buildPointZones, MIN( oldsize, newsize ) );
- BG_Free( level.buildPointZones );
- }
-
- level.buildPointZones = newZones;
- lastNumZones = g_humanRepeaterMaxZones.integer;
- }
-
level.frameMsec = trap_Milliseconds( );
}
@@ -2586,6 +2470,9 @@ void G_RunFrame( int levelTime )
G_SpawnClients( TEAM_HUMANS );
G_CalculateAvgPlayers( );
G_UpdateZaps( msec );
+
+ // update the power grid
+ G_UpdatePowerGrid( 0.001f * msec );
// see if it is time to end the level
CheckExitRules( );
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 4a28083..e4399a4 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -768,8 +768,8 @@ void CheckCkitRepair( gentity_t *ent )
if( tr.fraction < 1.0f && traceEnt->spawned && traceEnt->health > 0 &&
traceEnt->s.eType == ET_BUILDABLE && traceEnt->buildableTeam == TEAM_HUMANS )
{
- if(BG_Buildable(traceEnt->s.modelindex,NULL)->cuboid)
- if(!BG_CuboidAttributes(traceEnt->s.modelindex)->repairable)
+ if( BG_Buildable( traceEnt->s.modelindex, NULL )->cuboid )
+ if( !BG_CuboidAttributes( traceEnt->s.modelindex )->repairable )
return;
bHealth = BG_Buildable( traceEnt->s.modelindex, traceEnt->cuboidSize )->health;
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index bf60cd0..71d848e 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -600,10 +600,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define DC_SPLASHDAMAGE 50
#define DC_SPLASHRADIUS 100
#define DC_ATTACK_PERIOD 10000 // how often to spam "under attack"
-#define DC_HEALRATE 4
+#define DC_HEALRATE 250 // +1 HP every this amount of time
#define DC_RANGE 1000
#define DC_VALUE HBVM(DC_BP)
-#define MAX_DCS_PER_BUILDABLE 2
#define ARMOURY_BP 10
#define ARMOURY_BT 15000
@@ -612,7 +611,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define ARMOURY_SPLASHRADIUS 100
#define ARMOURY_VALUE HBVM(ARMOURY_BP)
-#define REACTOR_BP 0
+#define REACTOR_BP 36
#define REACTOR_BT 30000
#define REACTOR_HEALTH HBHM(930)
#define REACTOR_SPLASHDAMAGE 200
@@ -623,7 +622,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define REACTOR_ATTACK_DCC_REPEAT 1000
#define REACTOR_ATTACK_DCC_RANGE 150.0f
#define REACTOR_ATTACK_DCC_DAMAGE 40
-#define REACTOR_VALUE HBVM(30)
+#define REACTOR_VALUE HBVM(REACTOR_BP)
#define REPEATER_BP 4
#define REPEATER_BT 15000
@@ -632,6 +631,86 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define REPEATER_SPLASHRADIUS 100
#define REPEATER_VALUE HBVM(REPEATER_BP)
+#define CAPBANK_BP 10
+#define CAPBANK_BT 20000
+#define CAPBANK_HEALTH HBHM(310)
+#define CAPBANK_SPLASHDAMAGE 70
+#define CAPBANK_SPLASHRADIUS 140
+#define CAPBANK_VALUE HBVM(CAPBANK_BP)
+
+#define RTG_BP 14
+#define RTG_BT 20000
+#define RTG_HEALTH HBHM(460)
+#define RTG_SPLASHDAMAGE 120
+#define RTG_SPLASHRADIUS 150
+#define RTG_VALUE HBVM(15)
+#define RTG_YIELD 0.15
+#define RTG_STORAGE 15
+
+#define REFINERY_BP 16
+#define REFINERY_BT 20000
+#define REFINERY_HEALTH HBHM(310)
+#define REFINERY_SPLASHDAMAGE 100
+#define REFINERY_SPLASHRADIUS 150
+#define REFINERY_VALUE HBVM(REFINERY_BP)
+#define REFINERY_YIELD 0.35 // at 2Hz
+#define REFINERY_STORAGE 30
+
+/*
+ * POWER GRID settings
+ *
+ * All units are SI:
+ * resistance (R) - ohms
+ * voltage (V) - volts
+ * current (I) - amperes
+ * capacity (C) - farads
+ */
+
+//settings for buildables that are not a part of the power grid
+#define DEFAULT_POWER_SETTINGS qfalse, qfalse, 0.0f, 0.0f, qfalse
+
+#define RESISTANCE(i,pc) (POWER_VOLTAGE/(i)*(pc))
+
+#define POWER_VOLTAGE 100.0f
+
+#define RTG_RESISTANCE 5.0f
+
+#define REACTOR_RESISTANCE 1.0f
+
+#define CAPBANK_RESISTANCE 0.05f
+#define CAPBANK_CAPACITY 2.0f
+
+#define PREBUILD_CURRENT 7.0f
+#define PREBUILD_RESISTANCE RESISTANCE(PREBUILD_CURRENT,0.8f)
+
+#define MEDISTAT_I_IDLE 0.25f
+#define MEDISTAT_R_IDLE RESISTANCE(MEDISTAT_I_IDLE,0.35f)
+#define MEDISTAT_I_ACTIVE 1.0f
+#define MEDISTAT_R_ACTIVE RESISTANCE(MEDISTAT_I_ACTIVE,0.75f)
+
+#define ARMOURY_CURRENT 0.1f
+#define ARMOURY_RESISTANCE RESISTANCE(ARMOURY_CURRENT,0.25f)
+
+#define TESLAGEN_I_IDLE 0.6f
+#define TESLAGEN_R_IDLE RESISTANCE(TESLAGEN_I_IDLE,0.52f)
+#define TESLAGEN_I_ACTIVE 5.0f
+#define TESLAGEN_R_ACTIVE RESISTANCE(TESLAGEN_I_ACTIVE,0.75f)
+
+#define MGTURRET_I_IDLE 0.3f
+#define MGTURRET_R_IDLE RESISTANCE(MGTURRET_I_IDLE,0.6f)
+#define MGTURRET_I_ACTIVE 2.0f
+#define MGTURRET_R_ACTIVE RESISTANCE(MGTURRET_I_ACTIVE,0.75f)
+
+#define DC_I_IDLE 0.4f
+#define DC_R_IDLE RESISTANCE(DC_I_IDLE,0.5f)
+#define DC_I_ACTIVE 5.0f
+#define DC_R_ACTIVE RESISTANCE(DC_I_ACTIVE,0.75f)
+
+#define REFINERY_I_IDLE 0.25f
+#define REFINERY_R_IDLE RESISTANCE(REFINERY_I_IDLE,0.55f)
+#define REFINERY_I_ACTIVE 4.0f
+#define REFINERY_R_ACTIVE RESISTANCE(REFINERY_I_ACTIVE,0.75f)
+
/*
* HUMAN misc
*/
@@ -664,6 +743,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define HUMAN_BUILDABLE_INACTIVE_TIME 90000
+#define CKIT_STORAGE 36
+
/*
* Misc
*/
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index 6566d5e..ef53272 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -1690,7 +1690,7 @@ static void UI_DrawInfoPane( menuItem_t *item, rectDef_t *rect, float text_x, fl
break;
case TEAM_HUMANS:
- string = "Power";
+ string = "Mass";
break;
default:
@@ -2580,24 +2580,41 @@ static void UI_LoadHumanBuilds( void )
{
int i, j = 0;
stage_t stage;
+ static buildable_t list [ 14 ] =
+ {
+ BA_H_RTG,
+ BA_H_REACTOR,
+ BA_H_SPAWN,
+ BA_H_REFINERY,
+ BA_H_MGTURRET,
+ BA_H_ARMOURY,
+ BA_H_MEDISTAT,
+ BA_H_REPEATER,
+ BA_H_CAPBANK,
+ BA_H_DCC,
+ BA_H_TESLAGEN,
+ BA_H_CUBOID1,
+ BA_H_CUBOID2,
+ BA_H_CUBOID3
+ };
UI_ParseCarriageList( );
stage = UI_GetCurrentHumanStage( );
uiInfo.humanBuildCount = 0;
- for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ )
+ for( i = 0; i < 14; i++ )
{
- if( BG_Buildable( i, NULL )->team == TEAM_HUMANS &&
- BG_Buildable( i, NULL )->buildWeapon & uiInfo.weapons &&
- BG_BuildableAllowedInStage( i, stage ) &&
- BG_BuildableIsAllowed( i ) )
+ if( BG_Buildable( list[ i ], NULL )->team == TEAM_HUMANS &&
+ BG_Buildable( list[ i ], NULL )->buildWeapon & uiInfo.weapons &&
+ BG_BuildableAllowedInStage( list[ i ], stage ) &&
+ BG_BuildableIsAllowed( list[ i ] ) )
{
- uiInfo.humanBuildList[ j ].text = BG_Buildable( i, NULL )->humanName;
+ uiInfo.humanBuildList[ j ].text = BG_Buildable( list[ i ], NULL )->humanName;
uiInfo.humanBuildList[ j ].cmd =
- String_Alloc( va( "cmd build %s\n", BG_Buildable( i, NULL )->name ) );
+ String_Alloc( va( "cmd build %s\n", BG_Buildable( list[ i ], NULL )->name ) );
uiInfo.humanBuildList[ j ].type = INFOTYPE_BUILDABLE;
- uiInfo.humanBuildList[ j ].v.buildable = i;
+ uiInfo.humanBuildList[ j ].v.buildable = list[ i ];
j++;