summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cgame/cg_buildable.c28
-rw-r--r--src/cgame/cg_draw.c16
-rw-r--r--src/cgame/cg_ents.c64
-rw-r--r--src/cgame/cg_event.c23
-rw-r--r--src/cgame/cg_local.h11
-rw-r--r--src/cgame/cg_main.c8
-rw-r--r--src/cgame/cg_predict.c2
-rw-r--r--src/cgame/cg_servercmds.c217
-rw-r--r--src/cgame/cg_weapons.c42
-rw-r--r--src/game/bg_misc.c190
-rw-r--r--src/game/bg_pmove.c110
-rw-r--r--src/game/bg_public.h24
-rw-r--r--src/game/bg_slidemove.c25
-rw-r--r--src/game/g_active.c129
-rw-r--r--src/game/g_buildable.c80
-rw-r--r--src/game/g_client.c42
-rw-r--r--src/game/g_cmds.c253
-rw-r--r--src/game/g_combat.c41
-rw-r--r--src/game/g_local.h68
-rw-r--r--src/game/g_main.c77
-rw-r--r--src/game/g_missile.c4
-rw-r--r--src/game/g_svcmds.c4
-rw-r--r--src/game/g_target.c4
-rw-r--r--src/game/g_team.c4
-rw-r--r--src/game/g_trigger.c6
-rw-r--r--src/game/g_utils.c230
-rw-r--r--src/game/g_weapon.c248
-rw-r--r--src/game/tremulous.h70
-rw-r--r--src/ui/ui_main.c1
-rw-r--r--src/ui/ui_shared.c1
30 files changed, 1384 insertions, 638 deletions
diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c
index 3b462dec..0c334e7b 100644
--- a/src/cgame/cg_buildable.c
+++ b/src/cgame/cg_buildable.c
@@ -925,6 +925,8 @@ static void CG_BuildableHealthBar( centity_t *cent )
}
}
+#define BUILDABLE_SOUND_PERIOD 500
+
/*
==================
CG_Buildable
@@ -940,6 +942,8 @@ void CG_Buildable( centity_t *cent )
float rotAngle;
buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex );
float scale;
+ int health;
+ float healthScale;
//must be before EF_NODRAW check
if( team == BIT_ALIENS )
@@ -1132,12 +1136,34 @@ void CG_Buildable( centity_t *cent )
if( weapon->wim[ WPM_PRIMARY ].firingSound )
{
- trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, 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 );
}
+ health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT );
+ healthScale = (float)health / B_HEALTH_SCALE;
+
+ if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) )
+ {
+ if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time )
+ {
+ if( team == BIT_HUMANS )
+ {
+ int i = rand( ) % 4;
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
+ }
+ else if( team == BIT_ALIENS )
+ trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
+
+ cent->lastBuildableDamageSoundTime = cg.time;
+ }
+ }
+
+ cent->lastBuildableHealthScale = healthScale;
+
//smoke etc for damaged buildables
CG_BuildableParticleEffects( cent );
}
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index f5fb5487..9cb1740c 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -896,7 +896,7 @@ static void CG_DrawPlayerPoisonBarbs( rectDef_t *rect, vec4_t color, qhandle_t s
qboolean vertical;
int iconsize, numBarbs, i;
- BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &numBarbs, NULL, NULL );
+ BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &numBarbs, NULL );
if( height > width )
{
@@ -981,7 +981,7 @@ static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color )
break;
default:
- BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &value, NULL, NULL );
+ BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &value, NULL );
break;
}
@@ -1140,7 +1140,7 @@ static void CG_DrawPlayerClipsValue( rectDef_t *rect, vec4_t color )
break;
default:
- BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, NULL, &value, NULL );
+ BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, NULL, &value );
if( value > -1 )
{
@@ -1433,7 +1433,7 @@ float CG_GetValue( int ownerDraw )
int value;
BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups,
- &value, NULL, NULL );
+ &value, NULL );
return value;
}
@@ -1444,7 +1444,7 @@ float CG_GetValue( int ownerDraw )
int value;
BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups,
- NULL, &value, NULL );
+ NULL, &value );
return value;
}
@@ -2309,15 +2309,15 @@ CG_DrawWeaponIcon
*/
void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color )
{
- int ammo, clips, maxAmmo, maxClips;
+ int ammo, clips, maxAmmo;
centity_t *cent;
playerState_t *ps;
cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
- BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips, NULL );
- BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, &maxClips, NULL );
+ BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips );
+ BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, NULL );
// don't display if dead
if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c
index 1ed6cb2e..df269155 100644
--- a/src/cgame/cg_ents.c
+++ b/src/cgame/cg_ents.c
@@ -758,6 +758,64 @@ static void CG_LightFlare( centity_t *cent )
/*
=========================
+CG_Lev2ZapChain
+=========================
+*/
+static void CG_Lev2ZapChain( centity_t *cent )
+{
+ int i = 0;
+ entityState_t *es;
+ vec3_t start, end;
+ centity_t *source, *target;
+
+ es = &cent->currentState;
+
+ if( es->time > 0 )
+ {
+ source = &cg_entities[ es->powerups ];
+ target = &cg_entities[ es->time ];
+
+ if( es->powerups == cg.predictedPlayerState.clientNum )
+ VectorCopy( cg.predictedPlayerState.origin, start );
+ else
+ VectorCopy( source->currentState.pos.trBase, start );
+
+ VectorCopy( target->currentState.pos.trBase, end );
+
+ CG_DynamicLightningBolt( cgs.media.lightningShader, start, end,
+ 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(),
+ qtrue, 1.0, 0, i*i*3 );
+ }
+
+ if( es->time2 > 0 )
+ {
+ source = &cg_entities[ es->time ];
+ target = &cg_entities[ es->time2 ];
+
+ VectorCopy( source->currentState.pos.trBase, start );
+ VectorCopy( target->currentState.pos.trBase, end );
+
+ CG_DynamicLightningBolt( cgs.media.lightningShader, start, end,
+ 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(),
+ qtrue, 1.0, 0, i*i*3 );
+ }
+
+ if( es->constantLight > 0 )
+ {
+ source = &cg_entities[ es->time2 ];
+ target = &cg_entities[ es->constantLight ];
+
+ VectorCopy( source->currentState.pos.trBase, start );
+ VectorCopy( target->currentState.pos.trBase, end );
+
+ CG_DynamicLightningBolt( cgs.media.lightningShader, start, end,
+ 1+((cg.time%((i+2)*(i+3)))+i)%2, 7 + (float)(i%3)*5 + 6.0*random(),
+ qtrue, 1.0, 0, i*i*3 );
+ }
+}
+
+/*
+=========================
CG_AdjustPositionForMover
Also called by client movement prediction code
@@ -1010,6 +1068,10 @@ static void CG_AddCEntity( centity_t *cent )
case ET_LIGHTFLARE:
CG_LightFlare( cent );
break;
+
+ case ET_LEV2_ZAP_CHAIN:
+ CG_Lev2ZapChain( cent );
+ break;
}
}
@@ -1122,7 +1184,7 @@ void CG_AddPacketEntities( void )
mins[ 2 ] = -zd;
maxs[ 2 ] = zu;
- CG_DrawBoundingBox( es->origin, mins, maxs );
+ CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs );
break;
default:
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c
index 049cea33..4ac8f984 100644
--- a/src/cgame/cg_event.c
+++ b/src/cgame/cg_event.c
@@ -376,7 +376,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
const char *s;
int clientNum;
clientInfo_t *ci;
- int steptime, i;
+ int steptime;
if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
steptime = 200;
@@ -767,28 +767,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
CG_AlienBuildableExplosion( position, dir );
break;
- case EV_HUMAN_BUILDABLE_DAMAGE:
- DEBUGNAME( "EV_HUMAN_BUILDABLE_DAMAGE" );
- i = rand( ) % 4;
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] );
- break;
-
- case EV_ALIEN_BUILDABLE_DAMAGE:
- DEBUGNAME( "EV_ALIEN_BUILDABLE_DAMAGE" );
- trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage );
- break;
-
case EV_TESLATRAIL:
DEBUGNAME( "EV_TESLATRAIL" );
cent->currentState.weapon = WP_TESLAGEN;
CG_TeslaTrail( es->origin2, es->pos.trBase, es->generic1, es->clientNum );
break;
- case EV_ALIENZAP:
- DEBUGNAME( "EV_ALIENZAP" );
- CG_AlienZap( es->origin2, es->pos.trBase, es->generic1, es->clientNum );
- break;
-
case EV_BULLET_HIT_WALL:
DEBUGNAME( "EV_BULLET_HIT_WALL" );
ByteToDir( es->eventParm, dir );
@@ -955,6 +939,11 @@ void CG_EntityEvent( centity_t *cent, vec3_t position )
}
break;
+ case EV_MEDKIT_USED:
+ DEBUGNAME( "EV_MEDKIT_USED" );
+ trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound );
+ break;
+
case EV_PLAYER_RESPAWN:
DEBUGNAME( "EV_PLAYER_RESPAWN" );
if( es->number == cg.clientNum )
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 821972d9..d12e8001 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -479,6 +479,8 @@ typedef struct centity_s
buildableAnimNumber_t buildableAnim; //persistant anim number
buildableAnimNumber_t oldBuildableAnim; //to detect when new anims are set
particleSystem_t *buildablePS;
+ float lastBuildableHealthScale;
+ int lastBuildableDamageSoundTime;
lightFlareStatus_t lfs;
@@ -1194,7 +1196,8 @@ typedef struct
qhandle_t jetPackHoverPS;
qhandle_t jetPackAscendPS;
- //TA:
+ sfxHandle_t medkitUseSound;
+
sfxHandle_t alienStageTransition;
sfxHandle_t humanStageTransition;
@@ -1220,8 +1223,6 @@ typedef struct
//TA: for wolf trail effects
qhandle_t sparkFlareShader;
- //TA: media used for armour switching stuff
-
//light armour
qhandle_t larmourHeadSkin;
qhandle_t larmourLegsSkin;
@@ -1393,7 +1394,6 @@ extern vmCvar_t cg_debugAnim;
extern vmCvar_t cg_debugPosition;
extern vmCvar_t cg_debugEvents;
extern vmCvar_t cg_teslaTrailTime;
-extern vmCvar_t cg_alienZapTime;
extern vmCvar_t cg_railTrailTime;
extern vmCvar_t cg_errorDecay;
extern vmCvar_t cg_nopredict;
@@ -1467,7 +1467,7 @@ extern vmCvar_t cg_consoleLatency;
extern vmCvar_t cg_lightFlare;
extern vmCvar_t cg_debugParticles;
extern vmCvar_t cg_debugPVS;
-extern vmCvar_t cg_disableBuildWarnings;
+extern vmCvar_t cg_disableWarningDialogs;
extern vmCvar_t cg_disableScannerPlane;
//TA: hack to get class an carriage through to UI module
@@ -1663,7 +1663,6 @@ void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboole
void CG_ShotgunFire( entityState_t *es );
void CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum );
-void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum );
void CG_AddViewWeapon (playerState_t *ps);
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent );
void CG_DrawItemSelect( rectDef_t *rect, vec4_t color );
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 056fd76f..8a657ab7 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -96,7 +96,6 @@ upgradeInfo_t cg_upgrades[ 32 ];
buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ];
vmCvar_t cg_teslaTrailTime;
-vmCvar_t cg_alienZapTime;
vmCvar_t cg_railTrailTime;
vmCvar_t cg_centertime;
vmCvar_t cg_runpitch;
@@ -200,7 +199,7 @@ vmCvar_t cg_consoleLatency;
vmCvar_t cg_lightFlare;
vmCvar_t cg_debugParticles;
vmCvar_t cg_debugPVS;
-vmCvar_t cg_disableBuildWarnings;
+vmCvar_t cg_disableWarningDialogs;
vmCvar_t cg_disableScannerPlane;
//TA: hack to get class and carriage through to UI module
@@ -254,7 +253,6 @@ static cvarTable_t cvarTable[ ] =
{ &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
{ &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE },
{ &cg_teslaTrailTime, "cg_teslaTrailTime", "600", CVAR_ARCHIVE },
- { &cg_alienZapTime, "cg_alienZapTime", "500", CVAR_ARCHIVE },
{ &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE },
{ &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
{ &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
@@ -305,7 +303,7 @@ static cvarTable_t cvarTable[ ] =
{ &cg_lightFlare, "cg_lightFlare", "3", CVAR_ARCHIVE },
{ &cg_debugParticles, "cg_debugParticles", "0", CVAR_CHEAT },
{ &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT },
- { &cg_disableBuildWarnings, "cg_disableBuildWarnings", "0", CVAR_ARCHIVE },
+ { &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE },
{ &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE },
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
@@ -680,6 +678,8 @@ static void CG_RegisterSounds( void )
cgs.media.jetpackDescendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/low.wav", qfalse );
cgs.media.jetpackIdleSound = trap_S_RegisterSound( "sound/upgrades/jetpack/idle.wav", qfalse );
cgs.media.jetpackAscendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/hi.wav", qfalse );
+
+ cgs.media.medkitUseSound = trap_S_RegisterSound( "sound/upgrades/medkit/medkit.wav", qfalse );
cgs.media.alienEvolveSound = trap_S_RegisterSound( "sound/player/alienevolve.wav", qfalse );
diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c
index 548efb86..d66fd653 100644
--- a/src/cgame/cg_predict.c
+++ b/src/cgame/cg_predict.c
@@ -63,7 +63,7 @@ void CG_BuildSolidList( void )
continue;
}
- if( cent->nextState.solid )
+ if( cent->nextState.solid && ent->eType != ET_MISSILE )
{
cg_solidEntities[ cg_numSolidEntities ] = cent;
cg_numSolidEntities++;
diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c
index e529d1ab..90b74f8c 100644
--- a/src/cgame/cg_servercmds.c
+++ b/src/cgame/cg_servercmds.c
@@ -556,7 +556,8 @@ static void CG_SetUIVars( void )
}
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
- if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) )
+ if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) &&
+ BG_FindPurchasableForUpgrade( i ) )
strcat( carriageCvar, va( "U%d ", i ) );
}
strcat( carriageCvar, "$" );
@@ -598,107 +599,158 @@ void CG_Menu( int menu )
break;
case MN_H_NOROOM:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the buildable turns "
"translucent green indicating a valid build location." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "There is no room to build here\n" );
+
break;
case MN_H_NOPOWER:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no power remaining. Free up power by destroying existing "
"buildable objects." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "There is no power remaining\n" );
+
break;
case MN_H_NOTPOWERED:
- trap_Cvar_Set( "ui_dialog", "This buildable is not powered. Build a reactor and/or repeater in "
- "order to power it." );
- trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "This buildable is not powered. Build a Reactor and/or Repeater in "
+ "order to power it." );
+ trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ }
+ else
+ CG_Printf( "This buildable is not powered\n" );
+
break;
case MN_H_NORMAL:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. The surface is too steep or unsuitable "
"to build on. Please choose another site for this structure." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "Cannot build on this surface\n" );
+
break;
case MN_H_REACTOR:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
- trap_Cvar_Set( "ui_dialog", "There can only be one reactor. Destroy the existing one if you "
+ trap_Cvar_Set( "ui_dialog", "There can only be one Reactor. Destroy the existing one if you "
"wish to move it." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "There can only be one Reactor\n" );
+
break;
case MN_H_REPEATER:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no power here. If available, a Repeater may be used to "
"transmit power to this location." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "There is no power here\n" );
+
break;
case MN_H_NODCC:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no Defense Computer. A Defense Computer is needed to build "
"this." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "There is no Defense Computer\n" );
+
break;
case MN_H_TNODEWARN:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
- trap_Cvar_Set( "ui_dialog", "WARNING: This telenode will not be powered. Build near a power "
+ trap_Cvar_Set( "ui_dialog", "WARNING: This Telenode will not be powered. Build near a power "
"structure to prevent seeing this message again." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "This Telenode will not be powered\n" );
+
break;
case MN_H_RPTWARN:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
- trap_Cvar_Set( "ui_dialog", "WARNING: This repeater will not be powered as there is no parent "
- "reactor providing power. Build a reactor." );
+ trap_Cvar_Set( "ui_dialog", "WARNING: This Repeater will not be powered as there is no parent "
+ "Reactor providing power. Build a Reactor." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "This Repeater will not be powered\n" );
+
break;
case MN_H_RPTWARN2:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
- trap_Cvar_Set( "ui_dialog", "This area already has power. A repeater is not required here." );
+ trap_Cvar_Set( "ui_dialog", "This area already has power. A Repeater is not required here." );
trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
}
+ else
+ CG_Printf( "This area already has power\n" );
+
break;
case MN_H_NOSLOTS:
- trap_Cvar_Set( "ui_dialog", "You have no room to carry this. Please sell any conflicting "
- "upgrades before purchasing this item." );
- trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "You have no room to carry this. Please sell any conflicting "
+ "upgrades before purchasing this item." );
+ trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ }
+ else
+ CG_Printf( "You have no room to carry this\n" );
+
break;
case MN_H_NOFUNDS:
- trap_Cvar_Set( "ui_dialog", "Insufficient funds. You do not have enough credits to perform this "
- "action." );
- trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "Insufficient funds. You do not have enough credits to perform this "
+ "action." );
+ trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ }
+ else
+ CG_Printf( "Insufficient funds\n" );
+
break;
case MN_H_ITEMHELD:
- trap_Cvar_Set( "ui_dialog", "You already hold this item. It is not possible to carry multiple items "
- "of the same type." );
- trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "You already hold this item. It is not possible to carry multiple items "
+ "of the same type." );
+ trap_SendConsoleCommand( "menu tremulous_human_dialog\n" );
+ }
+ else
+ CG_Printf( "You already hold this item\n" );
+
break;
@@ -706,103 +758,160 @@ void CG_Menu( int menu )
case MN_A_NOROOM:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the structure turns "
"translucent green indicating a valid build location." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "There is no room to build here\n" );
+
break;
case MN_A_NOCREEP:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no creep here. You must build near existing Eggs or "
"the Overmind. Alien structures will not support themselves." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "There is no creep here\n" );
+
break;
case MN_A_NOOVMND:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to control "
"the structure you tried to place" );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "There is no Overmind\n" );
+
break;
case MN_A_OVERMIND:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "There can only be one Overmind. Destroy the existing one if you "
"wish to move it." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "There can only be one Overmind\n" );
+
break;
case MN_A_NOASSERT:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
- trap_Cvar_Set( "ui_dialog", "The Overmind cannot control anymore structures. Destroy existing "
+ trap_Cvar_Set( "ui_dialog", "The Overmind cannot control any more structures. Destroy existing "
"structures to build more." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "The Overmind cannot control any more structures\n" );
+
break;
case MN_A_SPWNWARN:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "WARNING: This spawn will not be controlled by an Overmind. "
"Build an Overmind to prevent seeing this message again." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "This spawn will not be controlled by an Overmind\n" );
+
break;
case MN_A_NORMAL:
- if( !cg_disableBuildWarnings.integer )
+ if( !cg_disableWarningDialogs.integer )
{
trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. This surface is too steep or unsuitable "
"to build on. Please choose another site for this structure." );
trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
}
+ else
+ CG_Printf( "Cannot build on this surface\n" );
+
break;
case MN_A_NOEROOM:
- trap_Cvar_Set( "ui_dialog", "There is no room to evolve here. Move away from walls or other "
- "nearby objects and try again." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "There is no room to evolve here. Move away from walls or other "
+ "nearby objects and try again." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "There is no room to evolve here\n" );
+
break;
case MN_A_TOOCLOSE:
- trap_Cvar_Set( "ui_dialog", "This location is too close to the enemy to evolve. "
- "Move away until you are no longer aware of the enemy's "
- "presence and try again." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "This location is too close to the enemy to evolve. "
+ "Move away until you are no longer aware of the enemy's "
+ "presence and try again." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "This location is too close to the enemy to evolve\n" );
+
break;
case MN_A_NOOVMND_EVOLVE:
- trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to allow "
- "you to upgrade." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to allow "
+ "you to upgrade." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "There is no Overmind\n" );
+
break;
case MN_A_HOVEL_OCCUPIED:
- trap_Cvar_Set( "ui_dialog", "This Hovel is occupied by another builder. Please find or build "
- "another." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "This Hovel is occupied by another builder. Please find or build "
+ "another." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "This Hovel is occupied by another builder\n" );
+
break;
case MN_A_HOVEL_BLOCKED:
- trap_Cvar_Set( "ui_dialog", "The exit to this Hovel is currently blocked. Please wait until it "
- "becomes clear then try again." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "The exit to this Hovel is currently blocked. Please wait until it "
+ "becomes clear then try again." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "The exit to this Hovel is currently blocked\n" );
+
break;
case MN_A_HOVEL_EXIT:
- trap_Cvar_Set( "ui_dialog", "The exit to this Hovel will always be blocked. Please choose "
- "a more suitable location." );
- trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ if( !cg_disableWarningDialogs.integer )
+ {
+ trap_Cvar_Set( "ui_dialog", "The exit to this Hovel would always be blocked. Please choose "
+ "a more suitable location." );
+ trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" );
+ }
+ else
+ CG_Printf( "The exit to this Hovel would always be blocked\n" );
+
break;
case MN_A_INFEST:
diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c
index afd9bb45..c67eaa04 100644
--- a/src/cgame/cg_weapons.c
+++ b/src/cgame/cg_weapons.c
@@ -186,36 +186,6 @@ void CG_TeslaTrail( vec3_t start, vec3_t end, int srcENum, int destENum )
VectorCopy( end, re->oldorigin );
}
-/*
-==========================
-CG_AlienZap
-==========================
-*/
-void CG_AlienZap( vec3_t start, vec3_t end, int srcENum, int destENum )
-{
- localEntity_t *le;
- refEntity_t *re;
-
- //add a bunch of bolt segments
- le = CG_AllocLocalEntity();
- re = &le->refEntity;
-
- le->leType = LE_LIGHTNING_BOLT;
- le->startTime = cg.time;
- le->endTime = cg.time + cg_alienZapTime.value;
- le->lifeRate = 1.0 / ( le->endTime - le->startTime );
- re->customShader = cgs.media.lightningShader;
-
- le->srcENum = srcENum;
- le->destENum = destENum;
- le->vOffset = 6.0f;
-
- le->maxRange = LEVEL2_AREAZAP_RANGE * M_ROOT3;
-
- VectorCopy( start, re->origin );
- VectorCopy( end, re->oldorigin );
-}
-
/*
=================
@@ -1362,16 +1332,12 @@ void CG_DrawItemSelect( rectDef_t *rect, vec4_t color )
int length;
int selectWindow;
qboolean vertical;
- int ammo, clips, maxAmmo, maxClips;
centity_t *cent;
playerState_t *ps;
cent = &cg_entities[ cg.snap->ps.clientNum ];
ps = &cg.snap->ps;
- BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips, NULL );
- BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, &maxClips, NULL );
-
// don't display if dead
if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
return;
@@ -1504,13 +1470,13 @@ CG_WeaponSelectable
*/
static qboolean CG_WeaponSelectable( int i )
{
- int ammo, clips, maxclips;
+ int ammo, clips;
- BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips, &maxclips );
+ BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips );
//TA: this is a pain in the ass
-/* if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
- return qfalse;*/
+ //if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) )
+ // return qfalse;
if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) )
return qfalse;
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 9922bf13..3c4134fd 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -153,7 +153,7 @@ buildableAttributes_t bg_buildableList[ ] =
BIT_ALIENS, //int team;
( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon;
BANIM_IDLE1, //int idleAnim;
- 500, //int nextthink;
+ 200, //int nextthink;
ACIDTUBE_BT, //int buildTime;
qfalse, //qboolean usable;
0, //int turretRange;
@@ -1475,7 +1475,7 @@ classAttributes_t bg_classList[ ] =
0.000f, //float bob;
1.0f, //float bobCycle;
350, //int steptime;
- 100, //float speed;
+ 600, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
6.0f, //float friction;
@@ -1512,7 +1512,7 @@ classAttributes_t bg_classList[ ] =
80, //int fov;
0.001f, //float bob;
2.0f, //float bobCycle;
- 200, //int steptime;
+ 150, //int steptime;
ABUILDER_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1550,7 +1550,7 @@ classAttributes_t bg_classList[ ] =
110, //int fov;
0.001f, //float bob;
2.0f, //float bobCycle;
- 200, //int steptime;
+ 100, //int steptime;
ABUILDER_UPG_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1628,7 +1628,7 @@ classAttributes_t bg_classList[ ] =
120, //int fov;
0.001f, //float bob;
1.8f, //float bobCycle;
- 25, //int steptime;
+ 60, //int steptime;
LEVEL1_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1667,7 +1667,7 @@ classAttributes_t bg_classList[ ] =
120, //int fov;
0.001f, //float bob;
1.8f, //float bobCycle;
- 25, //int steptime;
+ 60, //int steptime;
LEVEL1_UPG_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1706,7 +1706,7 @@ classAttributes_t bg_classList[ ] =
90, //int fov;
0.001f, //float bob;
1.5f, //float bobCycle;
- 60, //int steptime;
+ 80, //int steptime;
LEVEL2_SPEED, //float speed;
10.0f, //float acceleration;
2.0f, //float airAcceleration;
@@ -1745,7 +1745,7 @@ classAttributes_t bg_classList[ ] =
90, //int fov;
0.001f, //float bob;
1.5f, //float bobCycle;
- 60, //int steptime;
+ 80, //int steptime;
LEVEL2_UPG_SPEED, //float speed;
10.0f, //float acceleration;
2.0f, //float airAcceleration;
@@ -1784,7 +1784,7 @@ classAttributes_t bg_classList[ ] =
110, //int fov;
0.0005f, //float bob;
1.3f, //float bobCycle;
- 25, //int steptime;
+ 90, //int steptime;
LEVEL3_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1823,7 +1823,7 @@ classAttributes_t bg_classList[ ] =
110, //int fov;
0.0005f, //float bob;
1.3f, //float bobCycle;
- 25, //int steptime;
+ 90, //int steptime;
LEVEL3_UPG_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1862,7 +1862,7 @@ classAttributes_t bg_classList[ ] =
90, //int fov;
0.001f, //float bob;
1.1f, //float bobCycle;
- 60, //int steptime;
+ 100, //int steptime;
LEVEL4_SPEED, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -1901,7 +1901,7 @@ classAttributes_t bg_classList[ ] =
90, //int fov;
0.002f, //float bob;
1.0f, //float bobCycle;
- 200, //int steptime;
+ 100, //int steptime;
1.0f, //float speed;
10.0f, //float acceleration;
1.0f, //float airAcceleration;
@@ -2952,8 +2952,7 @@ weaponAttributes_t bg_weapons[ ] =
0, //int slots;
"blaster", //char *weaponName;
"Blaster", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -2976,8 +2975,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"rifle", //char *weaponName;
"Rifle", //char *weaponHumanName;
- RIFLE_CLIPSIZE, //int quan;
- RIFLE_SPAWNCLIPS, //int clips;
+ RIFLE_CLIPSIZE, //int maxAmmo;
RIFLE_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3000,8 +2998,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"shotgun", //char *weaponName;
"Shotgun", //char *weaponHumanName;
- SHOTGUN_SHELLS, //int quan;
- SHOTGUN_SPAWNCLIPS, //int clips;
+ SHOTGUN_SHELLS, //int maxAmmo;
SHOTGUN_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3024,8 +3021,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"flamer", //char *weaponName;
"Flame Thrower", //char *weaponHumanName;
- FLAMER_GAS, //int quan;
- 0, //int clips;
+ FLAMER_GAS, //int maxAmmo;
0, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3048,8 +3044,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"chaingun", //char *weaponName;
"Chaingun", //char *weaponHumanName;
- CHAINGUN_BULLETS, //int quan;
- 0, //int clips;
+ CHAINGUN_BULLETS, //int maxAmmo;
0, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3072,8 +3067,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"mdriver", //char *weaponName;
"Mass Driver", //char *weaponHumanName;
- MDRIVER_CLIPSIZE, //int quan;
- MDRIVER_SPAWNCLIPS, //int clips;
+ MDRIVER_CLIPSIZE, //int maxAmmo;
MDRIVER_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
qtrue, //int usesEnergy;
@@ -3096,8 +3090,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"prifle", //char *weaponName;
"Pulse Rifle", //char *weaponHumanName;
- PRIFLE_CLIPS, //int quan;
- PRIFLE_SPAWNCLIPS, //int clips;
+ PRIFLE_CLIPS, //int maxAmmo;
PRIFLE_MAXCLIPS, //int maxClips;
qfalse, //int infiniteAmmo;
qtrue, //int usesEnergy;
@@ -3120,8 +3113,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"lcannon", //char *weaponName;
"Lucifer Cannon", //char *weaponHumanName;
- LCANNON_AMMO, //int quan;
- 0, //int clips;
+ LCANNON_AMMO, //int maxAmmo;
0, //int maxClips;
qfalse, //int infiniteAmmo;
qtrue, //int usesEnergy;
@@ -3144,8 +3136,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"lgun", //char *weaponName;
"Las Gun", //char *weaponHumanName;
- LASGUN_AMMO, //int quan;
- 0, //int clips;
+ LASGUN_AMMO, //int maxAmmo;
0, //int maxClips;
qfalse, //int infiniteAmmo;
qtrue, //int usesEnergy;
@@ -3168,8 +3159,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"psaw", //char *weaponName;
"Pain Saw", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3192,8 +3182,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_NONE, //int slots;
"grenade", //char *weaponName;
"Grenade", //char *weaponHumanName;
- 1, //int quan;
- 0, //int clips;
+ 1, //int maxAmmo;
0, //int maxClips;
qfalse, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3216,8 +3205,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"ckit", //char *weaponName;
"Construction Kit", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3240,8 +3228,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"ackit", //char *weaponName;
"Adv Construction Kit",//char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3264,8 +3251,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"abuild", //char *weaponName;
"Alien build weapon", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3288,8 +3274,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"abuild2", //char *weaponName;
"Alien build weapon2",//char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3312,8 +3297,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"bite", //char *weaponName;
"Bite", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3336,8 +3320,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"pounce", //char *weaponName;
"Claw and pounce", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3360,8 +3343,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"pounce_upgrade", //char *weaponName;
"Claw and pounce (upgrade)", //char *weaponHumanName;
- 3, //int quan;
- 0, //int clips;
+ 3, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3384,8 +3366,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"grabandclaw", //char *weaponName;
"Claws", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3408,8 +3389,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"grabandclaw_upgrade",//char *weaponName;
"Claws Upgrade", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3432,8 +3412,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"areazap", //char *weaponName;
"Area Zap", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3456,8 +3435,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"directzap", //char *weaponName;
"Directed Zap", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3480,8 +3458,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"charge", //char *weaponName;
"Charge", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3504,8 +3481,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"lockblob", //char *weaponName;
"Lock Blob", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3528,8 +3504,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"hive", //char *weaponName;
"Hive", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3552,8 +3527,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"mgturret", //char *weaponName;
"Machinegun Turret", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qfalse, //int usesEnergy;
@@ -3576,8 +3550,7 @@ weaponAttributes_t bg_weapons[ ] =
SLOT_WEAPON, //int slots;
"teslagen", //char *weaponName;
"Tesla Generator", //char *weaponHumanName;
- 0, //int quan;
- 0, //int clips;
+ 0, //int maxAmmo;
0, //int maxClips;
qtrue, //int infiniteAmmo;
qtrue, //int usesEnergy;
@@ -3722,7 +3695,7 @@ char *BG_FindHumanNameForWeapon( int weapon )
BG_FindAmmoForWeapon
==============
*/
-void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips )
+void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips )
{
int i;
@@ -3730,10 +3703,8 @@ void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips )
{
if( bg_weapons[ i ].weaponNum == weapon )
{
- if( quan != NULL )
- *quan = bg_weapons[ i ].quan;
- if( clips != NULL )
- *clips = bg_weapons[ i ].clips;
+ if( maxAmmo != NULL )
+ *maxAmmo = bg_weapons[ i ].maxAmmo;
if( maxClips != NULL )
*maxClips = bg_weapons[ i ].maxClips;
@@ -4009,6 +3980,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"larmour", //char *upgradeName;
"Light Armour", //char *upgradeHumanName;
"icons/iconu_larmour",
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4019,16 +3991,18 @@ upgradeAttributes_t bg_upgrades[ ] =
"helmet", //char *upgradeName;
"Helmet", //char *upgradeHumanName;
"icons/iconu_helmet",
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
- UP_ANTITOXIN, //int upgradeNum;
- ANTITOXIN_PRICE, //int price;
+ UP_MEDKIT, //int upgradeNum;
+ MEDKIT_PRICE, //int price;
( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages
SLOT_NONE, //int slots;
- "atoxin", //char *upgradeName;
- "Anti-toxin", //char *upgradeHumanName;
+ "medkit", //char *upgradeName;
+ "Medkit", //char *upgradeHumanName;
"icons/iconu_atoxin",
+ qfalse, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4039,6 +4013,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"battpack", //char *upgradeName;
"Battery Pack", //char *upgradeHumanName;
"icons/iconu_battpack",
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4049,6 +4024,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"jetpack", //char *upgradeName;
"Jet Pack", //char *upgradeHumanName;
"icons/iconu_jetpack",
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4059,6 +4035,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"bsuit", //char *upgradeName;
"Battlesuit", //char *upgradeHumanName;
"icons/iconu_bsuit",
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4069,6 +4046,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"gren", //char *upgradeName;
"Grenade", //char *upgradeHumanName;
0,
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4079,6 +4057,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"ammo", //char *upgradeName;
"Ammunition", //char *upgradeHumanName;
0,
+ qtrue, //qboolean purchasable
WUT_HUMANS //WUTeam_t team;
}
};
@@ -4226,6 +4205,24 @@ char *BG_FindIconForUpgrade( int upgrade )
/*
==============
+BG_FindPurchasableForUpgrade
+==============
+*/
+qboolean BG_FindPurchasableForUpgrade( int upgrade )
+{
+ int i;
+
+ for( i = 0; i < bg_numUpgrades; i++ )
+ {
+ if( bg_upgrades[ i ].upgradeNum == upgrade )
+ return bg_upgrades[ i ].purchasable;
+ }
+
+ return qfalse;
+}
+
+/*
+==============
BG_FindTeamForUpgrade
==============
*/
@@ -4420,7 +4417,6 @@ char *eventnames[ ] =
"EV_MISSILE_MISS",
"EV_MISSILE_MISS_METAL",
"EV_TESLATRAIL",
- "EV_ALIENZAP",
"EV_BULLET", // otherEntity is the shooter
"EV_LEV1_GRAB",
@@ -4443,9 +4439,9 @@ char *eventnames[ ] =
"EV_HUMAN_BUILDABLE_EXPLOSION",
"EV_ALIEN_BUILDABLE_EXPLOSION",
"EV_ALIEN_ACIDTUBE",
- "EV_HUMAN_BUILDABLE_DAMAGE",
- "EV_ALIEN_BUILDABLE_DAMAGE",
+ "EV_MEDKIT_USED",
+
"EV_ALIEN_EVOLVE",
"EV_ALIEN_EVOLVE_FAILED",
@@ -4751,25 +4747,22 @@ BG_UnpackAmmoArray
Extract the ammo quantity from the array
========================
*/
-void BG_UnpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips )
+void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips )
{
- int ammoarray[32];
+ int ammoarray[ 32 ];
int i;
for( i = 0; i <= 15; i++ )
- ammoarray[ i ] = ammo[ i ];
+ ammoarray[ i ] = psAmmo[ i ];
for( i = 16; i <= 31; i++ )
- ammoarray[ i ] = ammo2[ i - 16 ];
+ ammoarray[ i ] = psAmmo2[ i - 16 ];
- if( quan != NULL )
- *quan = ammoarray[ weapon ] & 0x03FF;
+ if( ammo != NULL )
+ *ammo = ammoarray[ weapon ] & 0x0FFF;
if( clips != NULL )
- *clips = ( ammoarray[ weapon ] >> 10 ) & 0x07;
-
- if( maxclips != NULL )
- *maxclips = ( ammoarray[ weapon ] >> 13 ) & 0x07;
+ *clips = ( ammoarray[ weapon ] >> 12 ) & 0x0F;
}
/*
@@ -4779,16 +4772,16 @@ BG_PackAmmoArray
Pack the ammo quantity into the array
========================
*/
-void BG_PackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips )
+void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips )
{
int weaponvalue;
- weaponvalue = quan | ( clips << 10 ) | ( maxclips << 13 );
+ weaponvalue = ammo | ( clips << 12 );
if( weapon <= 15 )
- ammo[ weapon ] = weaponvalue;
+ psAmmo[ weapon ] = weaponvalue;
else if( weapon >= 16 )
- ammo2[ weapon - 16 ] = weaponvalue;
+ psAmmo2[ weapon - 16 ] = weaponvalue;
}
/*
@@ -4798,15 +4791,18 @@ BG_WeaponIsFull
Check if a weapon has full ammo
========================
*/
-qboolean BG_WeaponIsFull( weapon_t weapon, int ammo[ ], int ammo2[ ] )
+qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] )
{
int maxAmmo, maxClips;
- int quan, clips;
+ int ammo, clips;
- BG_FindAmmoForWeapon( weapon, &maxAmmo, NULL, &maxClips );
- BG_UnpackAmmoArray( weapon, ammo, ammo2, &quan, &clips, NULL );
+ BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
+ BG_UnpackAmmoArray( weapon, psAmmo, psAmmo2, &ammo, &clips );
- return ( maxAmmo == quan ) && ( maxClips == clips );
+ if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) )
+ maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
+
+ return ( maxAmmo == ammo ) && ( maxClips == clips );
}
/*
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
index b28366be..e349958d 100644
--- a/src/game/bg_pmove.c
+++ b/src/game/bg_pmove.c
@@ -385,6 +385,15 @@ static float PM_CmdScale( usercmd_t *cmd )
modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) *
( LEVEL4_CHARGE_SPEED - 1.0f ) );
+ //slow player if charging up for a pounce
+ if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) &&
+ cmd->buttons & BUTTON_ATTACK2 )
+ modifier *= LEVEL3_POUNCE_SPEED_MOD;
+
+ //slow the player if slow locked
+ if( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED )
+ modifier *= ABUILDER_BLOB_SPEED_MOD;
+
if( pm->ps->pm_type == PM_GRABBED )
modifier = 0.0f;
@@ -469,7 +478,8 @@ static void PM_CheckCharge( void )
if( pm->ps->weapon != WP_ALEVEL4 )
return;
- if( pm->cmd.buttons & BUTTON_ATTACK2 )
+ if( pm->cmd.buttons & BUTTON_ATTACK2 &&
+ !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
{
pm->ps->pm_flags &= ~PMF_CHARGE;
return;
@@ -2046,43 +2056,66 @@ static void PM_GroundTrace( void )
// if the trace didn't hit anything, we are in free fall
if( trace.fraction == 1.0f )
{
- PM_GroundTraceMissed( );
- pml.groundPlane = qfalse;
- pml.walking = qfalse;
-
- if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
+ qboolean steppedDown = qfalse;
+
+ // try to step down
+ if( pml.groundPlane != qfalse && PM_PredictStepMove( ) )
{
- ProjectPointOnPlane( movedir, pml.forward, refNormal );
- VectorNormalize( movedir );
-
- if( pm->cmd.forwardmove < 0 )
- VectorNegate( movedir, movedir );
+ //step down
+ point[ 0 ] = pm->ps->origin[ 0 ];
+ point[ 1 ] = pm->ps->origin[ 1 ];
+ point[ 2 ] = pm->ps->origin[ 2 ] - STEPSIZE;
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
- //allow strafe transitions
- if( pm->cmd.rightmove )
+ //if we hit something
+ if( trace.fraction < 1.0f )
{
- VectorCopy( pml.right, movedir );
-
- if( pm->cmd.rightmove < 0 )
- VectorNegate( movedir, movedir );
+ PM_StepEvent( pm->ps->origin, trace.endpos, refNormal );
+ VectorCopy( trace.endpos, pm->ps->origin );
+ steppedDown = qtrue;
}
-
- //trace into direction we are moving
- VectorMA( pm->ps->origin, 0.25f, movedir, point );
- pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
-
- if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
- ( trace.entityNum == ENTITYNUM_WORLD ) )
+ }
+
+ if( !steppedDown )
+ {
+ PM_GroundTraceMissed( );
+ pml.groundPlane = qfalse;
+ pml.walking = qfalse;
+
+ if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
{
- if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) )
+ ProjectPointOnPlane( movedir, pml.forward, refNormal );
+ VectorNormalize( movedir );
+
+ if( pm->cmd.forwardmove < 0 )
+ VectorNegate( movedir, movedir );
+
+ //allow strafe transitions
+ if( pm->cmd.rightmove )
+ {
+ VectorCopy( pml.right, movedir );
+
+ if( pm->cmd.rightmove < 0 )
+ VectorNegate( movedir, movedir );
+ }
+
+ //trace into direction we are moving
+ VectorMA( pm->ps->origin, 0.25f, movedir, point );
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask );
+
+ if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) &&
+ ( trace.entityNum == ENTITYNUM_WORLD ) )
{
- VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
- PM_CheckWallJump( );
+ if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) )
+ {
+ VectorCopy( trace.plane.normal, pm->ps->grapplePoint );
+ PM_CheckWallJump( );
+ }
}
}
+
+ return;
}
-
- return;
}
// check if getting thrown off the ground
@@ -2619,7 +2652,7 @@ Generates weapon events and modifes the weapon counter
static void PM_Weapon( void )
{
int addTime = 200; //default addTime - should never be used
- int ammo, clips, maxclips;
+ int ammo, clips, maxClips;
qboolean attack1 = qfalse;
qboolean attack2 = qfalse;
qboolean attack3 = qfalse;
@@ -2717,7 +2750,8 @@ static void PM_Weapon( void )
// start the animation even if out of ammo
- BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips );
+ BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips );
+ BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
// check for out of ammo
if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
@@ -2730,17 +2764,17 @@ static void PM_Weapon( void )
//done reloading so give em some ammo
if( pm->ps->weaponstate == WEAPON_RELOADING )
{
- if( maxclips > 0 )
+ if( maxClips > 0 )
{
clips--;
- BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL, NULL );
+ BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL );
}
if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) &&
BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) )
ammo = (int)( (float)ammo * BATTPACK_MODIFIER );
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips );
+ BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
//allow some time for the weapon to be raised
pm->ps->weaponstate = WEAPON_RAISING;
@@ -2967,13 +3001,13 @@ static void PM_Weapon( void )
else
ammo--;
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips );
+ BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
}
else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
{
//special case for slowblob
ammo--;
- BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips, maxclips );
+ BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips );
}
//FIXME: predicted angles miss a problem??
@@ -3175,11 +3209,11 @@ void trap_SnapVector( float *v );
void PmoveSingle( pmove_t *pmove )
{
- int ammo, clips, maxclips;
+ int ammo, clips;
pm = pmove;
- BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips, &maxclips );
+ BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips );
// this counter lets us debug movement problems with a journal
// by setting a conditional breakpoint fot the previous frame
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index c2b3805f..1104dccb 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -233,6 +233,8 @@ typedef enum
#define SS_BOOSTED 0x00000200
#define SS_SLOWLOCKED 0x00000400
#define SS_POISONCLOUDED 0x00000800
+#define SS_MEDKIT_ACTIVE 0x00001000
+#define SS_CHARGING 0x00002000
#define SB_VALID_TOGGLEBIT 0x00004000
@@ -369,7 +371,7 @@ typedef enum
UP_LIGHTARMOUR,
UP_HELMET,
- UP_ANTITOXIN,
+ UP_MEDKIT,
UP_BATTPACK,
UP_JETPACK,
UP_BATTLESUIT,
@@ -527,7 +529,6 @@ typedef enum
EV_MISSILE_MISS,
EV_MISSILE_MISS_METAL,
EV_TESLATRAIL,
- EV_ALIENZAP,
EV_BULLET, // otherEntity is the shooter
EV_LEV1_GRAB,
@@ -550,8 +551,8 @@ typedef enum
EV_HUMAN_BUILDABLE_EXPLOSION,
EV_ALIEN_BUILDABLE_EXPLOSION,
EV_ALIEN_ACIDTUBE,
- EV_HUMAN_BUILDABLE_DAMAGE,
- EV_ALIEN_BUILDABLE_DAMAGE,
+
+ EV_MEDKIT_USED,
EV_ALIEN_EVOLVE,
EV_ALIEN_EVOLVE_FAILED,
@@ -1031,8 +1032,7 @@ typedef struct
char *weaponName;
char *weaponHumanName;
- int quan;
- int clips;
+ int maxAmmo;
int maxClips;
qboolean infiniteAmmo;
qboolean usesEnergy;
@@ -1070,14 +1070,16 @@ typedef struct
char *icon;
+ qboolean purchasable;
+
WUTeam_t team;
} upgradeAttributes_t;
//TA:
-void BG_UnpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips );
-void BG_PackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips );
-qboolean BG_WeaponIsFull( weapon_t weapon, int ammo[ ], int ammo2[ ] );
+void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips );
+void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips );
+qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] );
void BG_AddWeaponToInventory( int weapon, int stats[ ] );
void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] );
qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] );
@@ -1175,7 +1177,7 @@ char *BG_FindModelsForWeapon( int weapon, int modelNum );
char *BG_FindIconForWeapon( int weapon );
char *BG_FindCrosshairForWeapon( int weapon );
int BG_FindCrosshairSizeForWeapon( int weapon );
-void BG_FindAmmoForWeapon( int weapon, int *quan, int *clips, int *maxClips );
+void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips );
qboolean BG_FindInfinteAmmoForWeapon( int weapon );
qboolean BG_FindUsesEnergyForWeapon( int weapon );
int BG_FindRepeatRate1ForWeapon( int weapon );
@@ -1197,6 +1199,7 @@ char *BG_FindNameForUpgrade( int upgrade );
int BG_FindUpgradeNumForName( char *name );
char *BG_FindHumanNameForUpgrade( int upgrade );
char *BG_FindIconForUpgrade( int upgrade );
+qboolean BG_FindPurchasableForUpgrade( int upgrade );
WUTeam_t BG_FindTeamForUpgrade( int upgrade );
// content masks
@@ -1235,6 +1238,7 @@ typedef enum
ET_ANIMMAPOBJ,
ET_MODELDOOR,
ET_LIGHTFLARE,
+ ET_LEV2_ZAP_CHAIN,
ET_EVENTS // any of the EV_* events can be added freestanding
// by setting eType to ET_EVENTS + eventNum
diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c
index e4f7f6c5..2ddd952b 100644
--- a/src/game/bg_slidemove.c
+++ b/src/game/bg_slidemove.c
@@ -305,21 +305,18 @@ qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
if( PM_SlideMove( gravity ) == 0 )
{
- if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
- {
- VectorCopy( start_o, down );
- VectorMA( down, -STEPSIZE, normal, down );
- pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
+ VectorCopy( start_o, down );
+ VectorMA( down, -STEPSIZE, normal, down );
+ pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
- //we can step down
- if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
- !trace.allsolid && pml.groundPlane != qfalse )
- {
- if( pm->debugLevel )
- Com_Printf( "%d: step down\n", c_pmove );
-
- stepped = qtrue;
- }
+ //we can step down
+ if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
+ !trace.allsolid && pml.groundPlane != qfalse )
+ {
+ if( pm->debugLevel )
+ Com_Printf( "%d: step down\n", c_pmove );
+
+ stepped = qtrue;
}
}
else
diff --git a/src/game/g_active.c b/src/game/g_active.c
index e3f09d69..581069cc 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -334,7 +334,7 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
else
client->ps.pm_type = PM_SPECTATOR;
- client->ps.speed = 400; // faster than normal
+ client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
client->ps.stats[ STAT_STAMINA ] = 0;
client->ps.stats[ STAT_MISC ] = 0;
@@ -440,7 +440,7 @@ qboolean ClientInactivityTimer( gclient_t *client )
if( level.time > client->inactivityTime - 10000 && !client->inactivityWarning )
{
client->inactivityWarning = qtrue;
- trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
+ G_SendCommandFromServer( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
}
}
@@ -542,23 +542,30 @@ void ClientTimerActions( gentity_t *ent, int msec )
if( client->ps.weapon == WP_ALEVEL4 )
{
if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 &&
- ( ucmd->forwardmove > 0 ) && !client->charging )
+ !client->charging )
{
client->charging = qfalse; //should already be off, just making sure
+ client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
- //trigger charge sound
- if( client->ps.stats[ STAT_MISC ] <= 0 )
- G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 );
-
- client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO );
-
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME )
- client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME;
+ if( ucmd->forwardmove > 0 )
+ {
+ //trigger charge sound...is quite annoying
+ //if( client->ps.stats[ STAT_MISC ] <= 0 )
+ // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 );
+
+ client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO );
+
+ if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME )
+ client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME;
+ }
+ else
+ client->ps.stats[ STAT_MISC ] = 0;
}
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging )
+ if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging ||
+ client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME )
{
- if( client->ps.stats[ STAT_MISC ] > 0 )
+ if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME )
{
client->ps.stats[ STAT_MISC ] -= 100;
@@ -566,20 +573,25 @@ void ClientTimerActions( gentity_t *ent, int msec )
G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 );
client->charging = qtrue;
+ client->ps.stats[ STAT_STATE ] |= SS_CHARGING;
//if the charger has stopped moving take a chunk of charge away
if( VectorLength( client->ps.velocity ) < 64.0f || aRight )
- client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] >> 1;
+ client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2;
//can't charge backwards
if( ucmd->forwardmove < 0 )
client->ps.stats[ STAT_MISC ] = 0;
}
+ else
+ client->ps.stats[ STAT_MISC ] = 0;
+
if( client->ps.stats[ STAT_MISC ] <= 0 )
{
client->ps.stats[ STAT_MISC ] = 0;
client->charging = qfalse;
+ client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
}
}
}
@@ -589,7 +601,7 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
int ammo;
- BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL, NULL );
+ BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL );
if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK )
client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE;
@@ -631,6 +643,43 @@ void ClientTimerActions( gentity_t *ent, int msec )
default:
break;
}
+
+ if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE )
+ {
+ int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime );
+
+ if( remainingStartupTime < 0 )
+ {
+ if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ ent->client->medKitHealthToRestore &&
+ ent->client->ps.pm_type != PM_DEAD )
+ {
+ ent->client->medKitHealthToRestore--;
+ ent->health++;
+ }
+ else
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ }
+ else
+ {
+ if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ ent->client->medKitHealthToRestore &&
+ ent->client->ps.pm_type != PM_DEAD )
+ {
+ //partial increase
+ if( level.time > client->medKitIncrementTime )
+ {
+ ent->client->medKitHealthToRestore--;
+ ent->health++;
+
+ client->medKitIncrementTime = level.time +
+ ( remainingStartupTime / MEDKIT_STARTUP_SPEED );
+ }
+ }
+ else
+ ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+ }
+ }
}
while( client->time1000 >= 1000 )
@@ -697,7 +746,7 @@ void ClientTimerActions( gentity_t *ent, int msec )
}
if( ent->health < client->ps.stats[ STAT_MAX_HEALTH ] &&
- ( client->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
+ ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier;
if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] )
@@ -713,13 +762,13 @@ void ClientTimerActions( gentity_t *ent, int msec )
{
int ammo, maxAmmo;
- BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL, NULL );
- BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL, NULL );
+ BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL );
+ BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL );
if( ammo < maxAmmo )
{
ammo++;
- BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0, 0 );
+ BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 );
}
}
}
@@ -833,14 +882,14 @@ void ClientEvents( gentity_t *ent, int oldEventSequence )
if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) )
{
- trap_SendServerCommand( ent - g_entities, va( "weaponswitch %d", j ) );
+ G_SendCommandFromServer( ent - g_entities, va( "weaponswitch %d", j ) );
break;
}
}
//only got the blaster to switch to
if( j == WP_NUM_WEAPONS )
- trap_SendServerCommand( ent - g_entities, va( "weaponswitch %d", WP_BLASTER ) );
+ G_SendCommandFromServer( ent - g_entities, va( "weaponswitch %d", WP_BLASTER ) );
//update ClientInfo
ClientUserinfoChanged( ent->client->ps.clientNum );
@@ -1022,16 +1071,33 @@ void ClientThink_real( gentity_t *ent )
client->ps.gravity = g_gravity.value;
- if( BG_InventoryContainsUpgrade( UP_ANTITOXIN, client->ps.stats ) &&
- BG_UpgradeIsActive( UP_ANTITOXIN, client->ps.stats ) )
+ if( BG_InventoryContainsUpgrade( UP_MEDKIT, client->ps.stats ) &&
+ BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) )
{
- if( client->ps.stats[ STAT_STATE ] & SS_POISONED )
+ //if currently using a medkit or have no need for a medkit now
+ if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ||
+ ( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] &&
+ !( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) )
+ {
+ BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
+ }
+ else
{
//remove anti toxin
- BG_DeactivateUpgrade( UP_ANTITOXIN, client->ps.stats );
- BG_RemoveUpgradeFromInventory( UP_ANTITOXIN, client->ps.stats );
+ BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats );
+ BG_RemoveUpgradeFromInventory( UP_MEDKIT, client->ps.stats );
client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+ client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME;
+
+ client->ps.stats[ STAT_STATE ] |= SS_MEDKIT_ACTIVE;
+ client->lastMedKitTime = level.time;
+ client->medKitHealthToRestore =
+ client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ];
+ client->medKitIncrementTime = level.time +
+ ( MEDKIT_STARTUP_TIME / MEDKIT_STARTUP_SPEED );
+
+ G_AddEvent( ent, EV_MEDKIT_USED, 0 );
}
}
@@ -1053,15 +1119,6 @@ void ClientThink_real( gentity_t *ent )
// set speed
client->ps.speed = g_speed.value * BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] );
- //TA: slow player if charging up for a pounce
- if( ( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG ) &&
- ucmd->buttons & BUTTON_ATTACK2 )
- client->ps.speed *= LEVEL3_POUNCE_SPEED_MOD;
-
- //TA: slow the player if slow locked
- if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED )
- client->ps.speed *= ABUILDER_BLOB_SPEED_MOD;
-
if( client->lastCreepSlowTime + CREEP_TIMEOUT < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED;
@@ -1069,7 +1126,7 @@ void ClientThink_real( gentity_t *ent )
if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) &&
BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) )
{
- if( client->lastDamageTime + JETPACK_DISABLE_TIME > level.time )
+ if( ent->lastDamageTime + JETPACK_DISABLE_TIME > level.time )
{
if( random( ) > JETPACK_DISABLE_CHANCE )
client->ps.pm_type = PM_NORMAL;
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 47815cb5..21a3d059 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -319,7 +319,7 @@ static qboolean findOvermind( gentity_t *self )
continue;
//if entity is an overmind calculate the distance to it
- if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned )
+ if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned && ent->health > 0 )
{
self->overmindNode = ent;
return qtrue;
@@ -424,19 +424,20 @@ creepSlow
Set any nearby humans' SS_CREEPSLOWED flag
================
*/
-static void creepSlow( buildable_t buildable, vec3_t origin )
+static void creepSlow( gentity_t *self )
{
- int entityList[ MAX_GENTITIES ];
- vec3_t range;
- vec3_t mins, maxs;
- int i, num;
- gentity_t *enemy;
- float creepSize = (float)BG_FindCreepSizeForBuildable( buildable );
+ int entityList[ MAX_GENTITIES ];
+ vec3_t range;
+ vec3_t mins, maxs;
+ int i, num;
+ gentity_t *enemy;
+ buildable_t buildable = self->s.modelindex;
+ float creepSize = (float)BG_FindCreepSizeForBuildable( buildable );
VectorSet( range, creepSize, creepSize, creepSize );
- VectorAdd( origin, range, maxs );
- VectorSubtract( origin, range, mins );
+ VectorAdd( self->s.origin, range, maxs );
+ VectorSubtract( self->s.origin, range, mins );
//find humans
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
@@ -445,7 +446,8 @@ static void creepSlow( buildable_t buildable, vec3_t origin )
enemy = &g_entities[ entityList[ i ] ];
if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS &&
- enemy->client->ps.groundEntityNum != ENTITYNUM_NONE )
+ enemy->client->ps.groundEntityNum != ENTITYNUM_NONE &&
+ G_Visible( self, enemy ) )
{
enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED;
enemy->client->lastCreepSlowTime = level.time;
@@ -642,7 +644,7 @@ void ASpawn_Think( gentity_t *self )
}
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -709,7 +711,7 @@ void AOvermind_Think( gentity_t *self )
}
//low on spawns
- if( level.numAlienSpawns <= 1 && level.time > self->overmindSpawnsTimer )
+ if( level.numAlienSpawns <= 0 && level.time > self->overmindSpawnsTimer )
{
self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD;
G_BroadcastEvent( EV_OVERMIND_SPAWNS, 0 );
@@ -731,8 +733,10 @@ void AOvermind_Think( gentity_t *self )
self->lastHealth = self->health;
}
+ else
+ self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD;
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -829,7 +833,7 @@ void ABarricade_Think( gentity_t *self )
return;
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -874,7 +878,7 @@ void AAcidTube_Damage( gentity_t *self )
self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS );
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -926,7 +930,7 @@ void AAcidTube_Think( gentity_t *self )
}
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
}
@@ -1002,7 +1006,7 @@ void AHive_Think( gentity_t *self )
}
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
}
@@ -1166,7 +1170,7 @@ void AHovel_Think( gentity_t *self )
G_setIdleBuildableAnim( self, BANIM_IDLE1 );
}
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + 200;
}
@@ -1242,7 +1246,7 @@ Called when an alien touches a booster
*/
void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
{
- int ammo, clips, maxClips;
+ int maxAmmo, maxClips;
gclient_t *client = other->client;
if( !self->spawned )
@@ -1262,8 +1266,8 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
return;
//restore ammo, if any
- BG_FindAmmoForWeapon( client->ps.weapon, &ammo, &clips, &maxClips );
- BG_PackAmmoArray( client->ps.weapon, client->ps.ammo, client->ps.powerups, ammo, clips, maxClips );
+ BG_FindAmmoForWeapon( client->ps.weapon, &maxAmmo, &maxClips );
+ BG_PackAmmoArray( client->ps.weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips );
if( !( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) )
{
@@ -1418,7 +1422,7 @@ void ATrapper_Think( gentity_t *self )
int range = BG_FindRangeForBuildable( self->s.modelindex );
int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex );
- creepSlow( self->s.modelindex, self->s.origin );
+ creepSlow( self );
self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex );
@@ -1520,14 +1524,14 @@ void HRpt_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
if( !BG_FindUsesEnergyForWeapon( weapon ) )
return;
- if( !BG_WeaponIsFull( weapon, ps->ammo, ps->powerups ) )
+ if( !BG_WeaponIsFull( weapon, ps->stats, ps->ammo, ps->powerups ) )
{
- BG_FindAmmoForWeapon( weapon, &maxAmmo, NULL, &maxClips );
+ BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
if( BG_InventoryContainsUpgrade( UP_BATTPACK, ps->stats ) )
maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
- BG_PackAmmoArray( weapon, ps->ammo, ps->powerups, maxAmmo, maxClips, maxClips );
+ BG_PackAmmoArray( weapon, ps->ammo, ps->powerups, maxAmmo, maxClips );
G_AddEvent( activator, EV_RPTUSE_SOUND, 0 );
activator->client->lastRefilTime = level.time;
@@ -1737,6 +1741,8 @@ void HMedistat_Think( gentity_t *self )
self->active = qtrue;
}
}
+ else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) )
+ BG_AddUpgradeToInventory( UP_MEDKIT, player->client->ps.stats );
}
}
}
@@ -1754,7 +1760,15 @@ void HMedistat_Think( gentity_t *self )
if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED )
self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED;
+ if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE )
+ self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE;
+
self->enemy->health++;
+
+ //if they're completely healed, give them a medkit
+ if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) )
+ BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats );
}
}
}
@@ -2347,7 +2361,8 @@ void G_BuildableThink( gentity_t *ent, int msec )
if( !ent->spawned )
ent->health += (int)( ceil( (float)bHealth / (float)( bTime * 0.001 ) ) );
- else if( ent->health > 0 && ent->health < bHealth && bRegen )
+ else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth &&
+ bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time )
ent->health += bRegen;
if( ent->health > bHealth )
@@ -2498,12 +2513,7 @@ itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance
//if none found...
if( i >= level.num_entities && buildable != BA_A_OVERMIND )
- {
- if( buildable == BA_A_SPAWN )
- reason = IBE_SPWNWARN;
- else
- reason = IBE_NOOVERMIND;
- }
+ reason = IBE_NOOVERMIND;
//can we only have one of these?
if( BG_FindUniqueTestForBuildable( buildable ) )
@@ -2532,10 +2542,6 @@ itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance
//tell player to build a repeater to provide power
if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER )
reason = IBE_REPEATER;
-
- //warn that the current spawn will not be externally powered
- if( buildable == BA_H_SPAWN )
- reason = IBE_TNODEWARN;
}
//this buildable requires a DCC
diff --git a/src/game/g_client.c b/src/game/g_client.c
index 23fca525..7c564be9 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -316,11 +316,10 @@ SelectAlienSpawnPoint
go to a random point that doesn't telefrag
================
*/
-gentity_t *SelectAlienSpawnPoint( void )
+gentity_t *SelectAlienSpawnPoint( vec3_t preference )
{
gentity_t *spot;
int count;
- int selection;
gentity_t *spots[ MAX_SPAWN_POINTS ];
if( level.numAlienSpawns <= 0 )
@@ -354,8 +353,7 @@ gentity_t *SelectAlienSpawnPoint( void )
if( !count )
return NULL;
- selection = rand() % count;
- return spots[ selection ];
+ return G_ClosestEnt( preference, spots, count );
}
@@ -366,11 +364,10 @@ SelectHumanSpawnPoint
go to a random point that doesn't telefrag
================
*/
-gentity_t *SelectHumanSpawnPoint( void )
+gentity_t *SelectHumanSpawnPoint( vec3_t preference )
{
gentity_t *spot;
int count;
- int selection;
gentity_t *spots[ MAX_SPAWN_POINTS ];
if( level.numHumanSpawns <= 0 )
@@ -404,8 +401,7 @@ gentity_t *SelectHumanSpawnPoint( void )
if( !count )
return NULL;
- selection = rand() % count;
- return spots[ selection ];
+ return G_ClosestEnt( preference, spots, count );
}
@@ -429,14 +425,14 @@ SelectTremulousSpawnPoint
Chooses a player start, deathmatch start, etc
============
*/
-gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t origin, vec3_t angles )
+gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles )
{
gentity_t *spot = NULL;
if( team == PTE_ALIENS )
- spot = SelectAlienSpawnPoint( );
+ spot = SelectAlienSpawnPoint( preference );
else if( team == PTE_HUMANS )
- spot = SelectHumanSpawnPoint( );
+ spot = SelectHumanSpawnPoint( preference );
//no available spots
if( !spot )
@@ -997,7 +993,7 @@ void ClientUserinfoChanged( int clientNum )
{
if( strcmp( oldname, client->pers.netname ) )
{
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname,
+ G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname,
client->pers.netname ) );
}
}
@@ -1158,7 +1154,7 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot )
// don't do the "xxx connected" messages if they were caried over from previous level
if( firstTime )
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );
+ G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );
// count current clients and rank for scoreboard
CalculateRanks( );
@@ -1218,10 +1214,12 @@ void ClientBegin( int clientNum )
tent->s.clientNum = ent->s.clientNum;
}
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) );
+ G_InitCommandQueue( clientNum );
+
+ G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) );
// request the clients PTR code
- trap_SendServerCommand( ent - g_entities, "ptrcrequest" );
+ G_SendCommandFromServer( ent - g_entities, "ptrcrequest" );
G_LogPrintf( "ClientBegin: %i\n", clientNum );
@@ -1254,7 +1252,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
int eventSequence;
char userinfo[ MAX_INFO_STRING ];
vec3_t up = { 0.0f, 0.0f, 1.0f };
- int ammo, clips, maxClips;
+ int maxAmmo, maxClips;
weapon_t weapon;
@@ -1387,6 +1385,7 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
if( ent->client->pers.classSelection == PCL_HUMAN )
{
BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats );
+ BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats );
weapon = client->pers.humanItemSelection;
}
else if( client->sess.sessionTeam != TEAM_SPECTATOR )
@@ -1394,9 +1393,9 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
else
weapon = WP_NONE;
- BG_FindAmmoForWeapon( weapon, &ammo, &clips, &maxClips );
+ BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
BG_AddWeaponToInventory( weapon, client->ps.stats );
- BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, ammo, clips, maxClips );
+ BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips );
ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection;
ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection;
@@ -1407,6 +1406,13 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
// health will count down towards max_health
ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25;
+
+ //if evolving scale health
+ if( ent == spawn )
+ {
+ ent->health *= ent->client->pers.evolveHealthFraction;
+ client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction;
+ }
//clear the credits array
for( i = 0; i < MAX_CLIENTS; i++ )
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index cc5b49c2..a5e9cc3a 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -67,7 +67,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s )
if( idnum < 0 || idnum >= level.maxclients )
{
- trap_SendServerCommand( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) );
+ G_SendCommandFromServer( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) );
return -1;
}
@@ -75,7 +75,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s )
if( cl->pers.connected != CON_CONNECTED )
{
- trap_SendServerCommand( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) );
+ G_SendCommandFromServer( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) );
return -1;
}
@@ -96,7 +96,7 @@ int G_ClientNumberFromString( gentity_t *to, char *s )
return idnum;
}
- trap_SendServerCommand( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) );
+ G_SendCommandFromServer( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) );
return -1;
}
@@ -170,7 +170,7 @@ void ScoreboardMessage( gentity_t *ent )
stringlength += j;
}
- trap_SendServerCommand( ent-g_entities, va( "scores %i %i %i%s", i,
+ G_SendCommandFromServer( ent-g_entities, va( "scores %i %i %i%s", i,
level.alienKills, level.humanKills, string ) );
}
@@ -198,13 +198,13 @@ qboolean CheatsOk( gentity_t *ent )
{
if( !g_cheats.integer )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) );
return qfalse;
}
if( ent->health <= 0 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) );
return qfalse;
}
@@ -261,7 +261,6 @@ Give items to a client
void Cmd_Give_f( gentity_t *ent )
{
char *name;
- int i;
qboolean give_all;
if( !CheatsOk( ent ) )
@@ -281,23 +280,6 @@ void Cmd_Give_f( gentity_t *ent )
return;
}
- if( give_all || Q_stricmp( name, "weapons" ) == 0 )
- {
- BG_AddWeaponToInventory( ( 1 << WP_NUM_WEAPONS ) - 1 - ( 1 << WP_NONE ), ent->client->ps.stats );
-
- if( !give_all )
- return;
- }
-
- if( give_all || Q_stricmp( name, "ammo" ) == 0 )
- {
- for( i = 0; i < MAX_WEAPONS; i++ )
- BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, 999, 0, 0 );
-
- if( !give_all )
- return;
- }
-
if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 )
{
int credits = atoi( name + 6 );
@@ -336,7 +318,7 @@ void Cmd_God_f( gentity_t *ent )
else
msg = "godmode ON\n";
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
+ G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -363,7 +345,7 @@ void Cmd_Notarget_f( gentity_t *ent )
else
msg = "notarget ON\n";
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
+ G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -388,7 +370,7 @@ void Cmd_Noclip_f( gentity_t *ent )
ent->client->noclip = !ent->client->noclip;
- trap_SendServerCommand( ent - g_entities, va( "print \"%s\"", msg ) );
+ G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) );
}
@@ -408,7 +390,7 @@ void Cmd_LevelShot_f( gentity_t *ent )
return;
BeginIntermission( );
- trap_SendServerCommand( ent - g_entities, "clientLevelShot" );
+ G_SendCommandFromServer( ent - g_entities, "clientLevelShot" );
}
/*
@@ -429,7 +411,7 @@ void Cmd_Kill_f( gentity_t *ent )
if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING )
{
- trap_SendServerCommand( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" );
return;
}
@@ -446,12 +428,12 @@ void Cmd_Kill_f( gentity_t *ent )
{
if( ent->suicideTime == 0 )
{
- trap_SendServerCommand( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" );
ent->suicideTime = level.time + 20000;
}
else if( ent->suicideTime > level.time )
{
- trap_SendServerCommand( ent-g_entities, "print \"Suicide cancelled\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Suicide cancelled\n\"" );
ent->suicideTime = 0;
}
}
@@ -502,7 +484,7 @@ void Cmd_Team_f( gentity_t *ent )
if( !strlen( s ) )
{
- trap_SendServerCommand( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.teamSelection ) );
+ G_SendCommandFromServer( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.teamSelection ) );
return;
}
@@ -539,16 +521,16 @@ void Cmd_Team_f( gentity_t *ent )
}
else
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) );
return;
}
G_ChangeTeam( ent, team );
if( team == PTE_ALIENS )
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " joined the aliens\n\"", ent->client->pers.netname ) );
+ G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the aliens\n\"", ent->client->pers.netname ) );
else if( team == PTE_HUMANS )
- trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " joined the humans\n\"", ent->client->pers.netname ) );
+ G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the humans\n\"", ent->client->pers.netname ) );
}
@@ -574,7 +556,7 @@ static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, cons
if( mode == SAY_TEAM && !OnSameTeam( ent, other ) )
return;
- trap_SendServerCommand( other-g_entities, va( "%s \"%s%c%c%s\"",
+ G_SendCommandFromServer( other-g_entities, va( "%s \"%s%c%c%s\"",
mode == SAY_TEAM ? "tchat" : "chat",
name, Q_COLOR_ESCAPE, color, message ) );
}
@@ -708,7 +690,7 @@ Cmd_Where_f
*/
void Cmd_Where_f( gentity_t *ent )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) );
}
/*
@@ -724,25 +706,25 @@ void Cmd_CallVote_f( gentity_t *ent )
if( !g_allowVote.integer )
{
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Voting not allowed here\n\"" );
return;
}
if( level.voteTime )
{
- trap_SendServerCommand( ent-g_entities, "print \"A vote is already in progress\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"A vote is already in progress\n\"" );
return;
}
if( ent->client->pers.voteCount >= MAX_VOTE_COUNT )
{
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of votes\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"You have called the maximum number of votes\n\"" );
return;
}
if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE )
{
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" );
return;
}
@@ -752,7 +734,7 @@ void Cmd_CallVote_f( gentity_t *ent )
if( strchr( arg1, ';' ) || strchr( arg2, ';' ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" );
return;
}
@@ -764,8 +746,8 @@ void Cmd_CallVote_f( gentity_t *ent )
else if( !Q_stricmp( arg1, "timelimit" ) ) { }
else
{
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, "
+ G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map <mapname>, "
"kick <player>, clientkick <clientnum>, "
"timelimit <time>\n\"" );
return;
@@ -801,7 +783,7 @@ void Cmd_CallVote_f( gentity_t *ent )
if( !*s )
{
- trap_SendServerCommand( ent-g_entities, "print \"nextmap not set\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"nextmap not set\n\"" );
return;
}
@@ -814,7 +796,7 @@ void Cmd_CallVote_f( gentity_t *ent )
Com_sprintf( level.voteDisplayString, sizeof( level.voteDisplayString ), "%s", level.voteString );
}
- trap_SendServerCommand( -1, va( "print \"%s called a vote\n\"", ent->client->pers.netname ) );
+ G_SendCommandFromServer( -1, va( "print \"%s called a vote\n\"", ent->client->pers.netname ) );
// start the voting, the caller autoamtically votes yes
level.voteTime = level.time;
@@ -843,23 +825,23 @@ void Cmd_Vote_f( gentity_t *ent )
if( !level.voteTime )
{
- trap_SendServerCommand( ent-g_entities, "print \"No vote in progress\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"No vote in progress\n\"" );
return;
}
if( ent->client->ps.eFlags & EF_VOTED )
{
- trap_SendServerCommand( ent-g_entities, "print \"Vote already cast\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Vote already cast\n\"" );
return;
}
if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE )
{
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" );
return;
}
- trap_SendServerCommand( ent-g_entities, "print \"Vote cast\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Vote cast\n\"" );
ent->client->ps.eFlags |= EF_VOTED;
@@ -902,25 +884,25 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
if( !g_allowVote.integer )
{
- trap_SendServerCommand( ent-g_entities, "print \"Voting not allowed here\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Voting not allowed here\n\"" );
return;
}
if( level.teamVoteTime[ cs_offset ] )
{
- trap_SendServerCommand( ent-g_entities, "print \"A team vote is already in progress\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"A team vote is already in progress\n\"" );
return;
}
if( ent->client->pers.teamVoteCount >= MAX_VOTE_COUNT )
{
- trap_SendServerCommand( ent-g_entities, "print \"You have called the maximum number of team votes\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"You have called the maximum number of team votes\n\"" );
return;
}
if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE )
{
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" );
return;
}
@@ -930,7 +912,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
if( strchr( arg1, ';' ) || strchr( arg2, ';' ) )
{
- trap_SendServerCommand( ent-g_entities, "print \"Invalid team vote string\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Invalid team vote string\n\"" );
return;
}
@@ -958,14 +940,14 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
if( i >= level.maxclients )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"%s is not a valid player on your team\n\"", arg2 ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"%s is not a valid player on your team\n\"", arg2 ) );
return;
}
}
else
{
- trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string\n\"" );
- trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: teamkick <player>\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Team vote commands are: teamkick <player>\n\"" );
return;
}
@@ -978,7 +960,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
continue;
if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
- trap_SendServerCommand( i, va("print \"%s called a team vote\n\"", ent->client->pers.netname ) );
+ G_SendCommandFromServer( i, va("print \"%s called a team vote\n\"", ent->client->pers.netname ) );
}
// start the voting, the caller autoamtically votes yes
@@ -1021,23 +1003,23 @@ void Cmd_TeamVote_f( gentity_t *ent )
if( !level.teamVoteTime[ cs_offset ] )
{
- trap_SendServerCommand( ent-g_entities, "print \"No team vote in progress\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"No team vote in progress\n\"" );
return;
}
if( ent->client->ps.eFlags & EF_TEAMVOTED )
{
- trap_SendServerCommand( ent-g_entities, "print \"Team vote already cast\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Team vote already cast\n\"" );
return;
}
if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE )
{
- trap_SendServerCommand( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to vote as spectator\n\"" );
return;
}
- trap_SendServerCommand( ent-g_entities, "print \"Team vote cast\n\"" );
+ G_SendCommandFromServer( ent-g_entities, "print \"Team vote cast\n\"" );
ent->client->ps.eFlags |= EF_TEAMVOTED;
@@ -1072,13 +1054,13 @@ void Cmd_SetViewpos_f( gentity_t *ent )
if( !g_cheats.integer )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) );
return;
}
if( trap_Argc( ) != 5 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"usage: setviewpos x y z yaw\n\"" ) );
return;
}
@@ -1184,7 +1166,7 @@ void Cmd_Class_f( gentity_t *ent )
currentClass == PCL_ALIEN_BUILDER0_UPG ) &&
ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot evolve until build timer expires\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot evolve until build timer expires\n\"" ) );
return;
}
@@ -1193,7 +1175,7 @@ void Cmd_Class_f( gentity_t *ent )
if( ent->client->pers.classSelection == PCL_NONE )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown class\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown class\n\"" ) );
return;
}
@@ -1230,6 +1212,14 @@ void Cmd_Class_f( gentity_t *ent )
//...check we can evolve to that class
if( numLevels >= 0 && BG_FindStagesForClass( ent->client->pers.classSelection, g_alienStage.integer ) )
{
+ ent->client->pers.evolveHealthFraction = (float)ent->client->ps.stats[ STAT_HEALTH ] /
+ (float)BG_FindHealthForClass( currentClass );
+
+ if( ent->client->pers.evolveHealthFraction < 0.0f )
+ ent->client->pers.evolveHealthFraction = 0.0f;
+ else if( ent->client->pers.evolveHealthFraction > 1.0f )
+ ent->client->pers.evolveHealthFraction = 1.0f;
+
//remove credit
G_AddCreditToClient( ent->client, -(short)numLevels, qtrue );
@@ -1241,7 +1231,7 @@ void Cmd_Class_f( gentity_t *ent )
else
{
ent->client->pers.classSelection = PCL_NONE;
- trap_SendServerCommand( ent-g_entities,
+ G_SendCommandFromServer( ent-g_entities,
va( "print \"You cannot evolve from your current class\n\"" ) );
return;
}
@@ -1272,11 +1262,11 @@ void Cmd_Class_f( gentity_t *ent )
}
ent->client->pers.classSelection = PCL_NONE;
- trap_SendServerCommand( ent-g_entities, va( "print \"You cannot spawn as this class\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You cannot spawn as this class\n\"" ) );
}
else
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown class\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown class\n\"" ) );
return;
}
}
@@ -1286,7 +1276,7 @@ void Cmd_Class_f( gentity_t *ent )
//humans cannot use this command whilst alive
if( ent->client->pers.classSelection != PCL_NONE )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be dead to use the class command\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You must be dead to use the class command\n\"" ) );
return;
}
@@ -1304,7 +1294,7 @@ void Cmd_Class_f( gentity_t *ent )
else
{
ent->client->pers.classSelection = PCL_NONE;
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown starting item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown starting item\n\"" ) );
return;
}
@@ -1316,7 +1306,7 @@ void Cmd_Class_f( gentity_t *ent )
ent->client->pers.classSelection = PCL_NONE;
ent->client->sess.sessionTeam = TEAM_FREE;
ClientSpawn( ent, NULL, NULL, NULL );
- trap_SendServerCommand( ent-g_entities, va( "print \"Join a team first\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Join a team first\n\"" ) );
}
}
@@ -1392,10 +1382,10 @@ void Cmd_ActivateItem_f( gentity_t *ent )
{
//force a weapon change
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) );
+ G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) );
}
else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
}
@@ -1420,7 +1410,7 @@ void Cmd_DeActivateItem_f( gentity_t *ent )
if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
BG_DeactivateUpgrade( upgrade, ent->client->ps.stats );
else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
}
@@ -1469,7 +1459,7 @@ void Cmd_ToggleItem_f( gentity_t *ent )
//force a weapon change
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) );
+ G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) );
}
else if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
{
@@ -1479,7 +1469,7 @@ void Cmd_ToggleItem_f( gentity_t *ent )
BG_ActivateUpgrade( upgrade, ent->client->ps.stats );
}
else
- trap_SendServerCommand( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You don't have the %s\n\"", s ) );
}
/*
@@ -1490,10 +1480,10 @@ G_GiveClientMaxAmmo
static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
{
int i;
- int quan, clips, maxClips;
+ int maxAmmo, maxClips;
qboolean weaponType;
- for( i = WP_NONE; i < WP_NUM_WEAPONS; i++ )
+ for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
{
if( buyingEnergyAmmo )
weaponType = BG_FindUsesEnergyForWeapon( i );
@@ -1502,9 +1492,10 @@ static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) &&
weaponType && !BG_FindInfinteAmmoForWeapon( i ) &&
- !BG_WeaponIsFull( i, ent->client->ps.ammo, ent->client->ps.powerups ) )
+ !BG_WeaponIsFull( i, ent->client->ps.stats,
+ ent->client->ps.ammo, ent->client->ps.powerups ) )
{
- BG_FindAmmoForWeapon( i, &quan, &clips, &maxClips );
+ BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips );
if( buyingEnergyAmmo )
{
@@ -1512,18 +1503,18 @@ static void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo )
ent->client->lastRefilTime = level.time;
if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
- quan = (int)( (float)quan * BATTPACK_MODIFIER );
+ maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
}
else
G_AddEvent( ent, EV_CHANGE_WEAPON, 0 );
BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups,
- quan, clips, maxClips );
+ maxAmmo, maxClips );
//force a weapon change
//FIXME: needs to work even if weapon is the same
//ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- //trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", ent->client->ps.weapon ) );
+ //G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", ent->client->ps.weapon ) );
}
}
}
@@ -1538,7 +1529,7 @@ void Cmd_Buy_f( gentity_t *ent )
char s[ MAX_TOKEN_CHARS ];
int i;
int weapon, upgrade, numItems = 0;
- int quan, clips, maxClips;
+ int maxAmmo, maxClips;
qboolean buyingEnergyAmmo = qfalse;
for( i = UP_NONE; i < UP_NUM_UPGRADES; i++ )
@@ -1576,7 +1567,7 @@ void Cmd_Buy_f( gentity_t *ent )
//no armoury nearby
if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) && !buyingEnergyAmmo )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
return;
}
@@ -1612,38 +1603,38 @@ void Cmd_Buy_f( gentity_t *ent )
if( BG_FindTeamForWeapon( weapon ) != WUT_HUMANS )
{
//shouldn't need a fancy dialog
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
return;
}
//are we /allowed/ to buy this?
if( !BG_FindPurchasableForWeapon( weapon ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
}
//are we /allowed/ to buy this?
if( !BG_FindStagesForWeapon( weapon, g_humanStage.integer ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
}
//add to inventory
BG_AddWeaponToInventory( weapon, ent->client->ps.stats );
- BG_FindAmmoForWeapon( weapon, &quan, &clips, &maxClips );
+ BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips );
if( BG_FindUsesEnergyForWeapon( weapon ) &&
BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) )
- quan = (int)( (float)quan * BATTPACK_MODIFIER );
+ maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER );
BG_PackAmmoArray( weapon, ent->client->ps.ammo, ent->client->ps.powerups,
- quan, clips, maxClips );
+ maxAmmo, maxClips );
//force a weapon change
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", weapon ) );
+ G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", weapon ) );
//set build delay/pounce etc to 0
ent->client->ps.stats[ STAT_MISC ] = 0;
@@ -1683,14 +1674,21 @@ void Cmd_Buy_f( gentity_t *ent )
if( BG_FindTeamForUpgrade( upgrade ) != WUT_HUMANS )
{
//shouldn't need a fancy dialog
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy alien items\n\"" ) );
+ return;
+ }
+
+ //are we /allowed/ to buy this?
+ if( !BG_FindPurchasableForUpgrade( upgrade ) )
+ {
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
}
//are we /allowed/ to buy this?
if( !BG_FindStagesForUpgrade( upgrade, g_humanStage.integer ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
}
@@ -1710,7 +1708,7 @@ void Cmd_Buy_f( gentity_t *ent )
}
else
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown item\n\"" ) );
}
//if the buyer previously had no items at all, force a new selection
@@ -1751,7 +1749,7 @@ void Cmd_Sell_f( gentity_t *ent )
//no armoury nearby
if( !G_BuildableRange( ent->client->ps.origin, 100, BA_H_ARMOURY ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You must be near a powered armoury\n\"" ) );
return;
}
@@ -1763,7 +1761,7 @@ void Cmd_Sell_f( gentity_t *ent )
//are we /allowed/ to sell this?
if( !BG_FindPurchasableForWeapon( weapon ) )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"You can't sell this weapon\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't sell this weapon\n\"" ) );
return;
}
@@ -1774,7 +1772,7 @@ void Cmd_Sell_f( gentity_t *ent )
if( ( weapon == WP_HBUILD || weapon == WP_HBUILD2 ) &&
ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
return;
}
@@ -1789,31 +1787,24 @@ void Cmd_Sell_f( gentity_t *ent )
{
//force a weapon change
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) );
+ G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) );
}
}
else if( upgrade != UP_NONE )
{
+ //are we /allowed/ to sell this?
+ if( !BG_FindPurchasableForUpgrade( upgrade ) )
+ {
+ G_SendCommandFromServer( ent-g_entities, va( "print \"You can't sell this item\n\"" ) );
+ return;
+ }
//remove upgrade if carried
if( BG_InventoryContainsUpgrade( upgrade, ent->client->ps.stats ) )
{
BG_RemoveUpgradeFromInventory( upgrade, ent->client->ps.stats );
if( upgrade == UP_BATTPACK )
- {
- int j;
-
- //remove energy
- for( j = WP_NONE; j < WP_NUM_WEAPONS; j++ )
- {
- if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) &&
- BG_FindUsesEnergyForWeapon( j ) &&
- !BG_FindInfinteAmmoForWeapon( j ) )
- {
- BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0, 0 );
- }
- }
- }
+ G_GiveClientMaxAmmo( ent, qtrue );
//add to funds
G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( upgrade ), qfalse );
@@ -1831,7 +1822,7 @@ void Cmd_Sell_f( gentity_t *ent )
if( ( i == WP_HBUILD || i == WP_HBUILD2 ) &&
ent->client->ps.stats[ STAT_MISC ] > 0 )
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot sell until build timer expires\n\"" ) );
continue;
}
@@ -1848,7 +1839,7 @@ void Cmd_Sell_f( gentity_t *ent )
{
//force a weapon change
ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH;
- trap_SendServerCommand( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) );
+ G_SendCommandFromServer( ent-g_entities, va( "weaponswitch %d", WP_BLASTER ) );
}
}
}
@@ -1872,7 +1863,7 @@ void Cmd_Sell_f( gentity_t *ent )
BG_FindUsesEnergyForWeapon( j ) &&
!BG_FindInfinteAmmoForWeapon( j ) )
{
- BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0, 0 );
+ BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0 );
}
}
}
@@ -1887,7 +1878,7 @@ void Cmd_Sell_f( gentity_t *ent )
}
}
else
- trap_SendServerCommand( ent-g_entities, va( "print \"Unknown item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown item\n\"" ) );
if( trap_Argc( ) >= 2 )
{
@@ -1982,7 +1973,7 @@ void Cmd_Build_f( gentity_t *ent )
}
else
{
- trap_SendServerCommand( ent-g_entities, va( "print \"Cannot build this item\n\"" ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"Cannot build this item\n\"" ) );
G_LogPrintf( "Client %d tried to build %d using weapon %d\n",
ent->client->ps.clientNum,
@@ -2004,7 +1995,7 @@ void Cmd_Echo_f( gentity_t *ent )
trap_Argv( 1, s, sizeof( s ) );
- trap_SendServerCommand( ent-g_entities, va( "print \"%s\n\"", s ) );
+ G_SendCommandFromServer( ent-g_entities, va( "print \"%s\n\"", s ) );
}
@@ -2216,7 +2207,7 @@ void Cmd_PTRCVerify_f( gentity_t *ent )
// valid code
if( connection->clientTeam != PTE_NONE )
- trap_SendServerCommand( ent->client->ps.clientNum, "ptrcconfirm" );
+ G_SendCommandFromServer( ent->client->ps.clientNum, "ptrcconfirm" );
// restore mapping
ent->client->pers.connection = connection;
@@ -2228,7 +2219,7 @@ void Cmd_PTRCVerify_f( gentity_t *ent )
if( connection )
{
- trap_SendServerCommand( ent->client->ps.clientNum,
+ G_SendCommandFromServer( ent->client->ps.clientNum,
va( "ptrcissue %d", connection->ptrCode ) );
}
}
@@ -2258,7 +2249,7 @@ void Cmd_PTRCRestore_f( gentity_t *ent )
{
if( ent->client->pers.joinedATeam )
{
- trap_SendServerCommand( ent - g_entities,
+ G_SendCommandFromServer( ent - g_entities,
"print \"You cannot use a PTR code after joining a team\n\"" );
}
else
@@ -2279,7 +2270,7 @@ void Cmd_PTRCRestore_f( gentity_t *ent )
}
else
{
- trap_SendServerCommand( ent - g_entities,
+ G_SendCommandFromServer( ent - g_entities,
va( "print \"\"%d\" is not a valid PTR code\n\"", code ) );
}
}
@@ -2297,11 +2288,11 @@ void Cmd_Test_f( gentity_t *ent )
/* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED;
ent->client->lastPoisonCloudedTime = level.time;
ent->client->lastPoisonCloudedClient = ent;
- trap_SendServerCommand( ent->client->ps.clientNum, "poisoncloud" );*/
+ G_SendCommandFromServer( ent->client->ps.clientNum, "poisoncloud" );*/
- ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
+/* ent->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
ent->client->lastPoisonTime = level.time;
- ent->client->lastPoisonClient = ent;
+ ent->client->lastPoisonClient = ent;*/
}
@@ -2347,11 +2338,7 @@ void ClientCommand( int clientNum )
// ignore all other commands when at intermission
if( level.intermissiontime )
- {
- //TA: prevent menu babble at the end of games
- /*Cmd_Say_f( ent, qfalse, qtrue );*/
return;
- }
if( Q_stricmp( cmd, "give" ) == 0 )
Cmd_Give_f( ent );
@@ -2416,5 +2403,5 @@ void ClientCommand( int clientNum )
else if( Q_stricmp( cmd, "test" ) == 0 )
Cmd_Test_f( ent );
else
- trap_SendServerCommand( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) );
+ G_SendCommandFromServer( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) );
}
diff --git a/src/game/g_combat.c b/src/game/g_combat.c
index 7b84ccc2..3df21614 100644
--- a/src/game/g_combat.c
+++ b/src/game/g_combat.c
@@ -368,6 +368,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
}
self->client->pers.classSelection = PCL_NONE; //TA: reset the classtype
+ VectorCopy( self->s.origin, self->client->pers.lastDeathLocation );
self->takedamage = qfalse; // can still be gibbed
@@ -1003,18 +1004,9 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
attacker->client->ps.persistant[ PERS_HITS ]++;
}
- if( damage < 1 )
- damage = 1;
-
take = damage;
save = 0;
- if( g_debugDamage.integer )
- {
- G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
- targ->health, take, asave );
- }
-
// add to the damage inflicted on a player this frame
// the total will be turned into screen blends and view angle kicks
// at the end of the frame
@@ -1051,7 +1043,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
{
if( !( targ->client->ps.stats[ STAT_STATE ] & SS_POISONED ) &&
!BG_InventoryContainsUpgrade( UP_BATTLESUIT, targ->client->ps.stats ) &&
- mod != MOD_LEVEL2_ZAP )
+ mod != MOD_LEVEL2_ZAP &&
+ targ->client->poisonImmunityTime < level.time )
{
targ->client->ps.stats[ STAT_STATE ] |= SS_POISONED;
targ->client->lastPoisonTime = level.time;
@@ -1060,24 +1053,24 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
}
+ if( take < 1 )
+ take = 1;
+
+ if( g_debugDamage.integer )
+ {
+ G_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number,
+ targ->health, take, asave );
+ }
+
// do the damage
if( take )
{
targ->health = targ->health - take;
- if( targ->s.eType == ET_BUILDABLE )
- {
- if( targ->biteam == BIT_ALIENS )
- G_AddEvent( targ, EV_ALIEN_BUILDABLE_DAMAGE, 0 );
- else if( targ->biteam == BIT_HUMANS )
- G_AddEvent( targ, EV_HUMAN_BUILDABLE_DAMAGE, 0 );
- }
-
if( targ->client )
- {
targ->client->ps.stats[ STAT_HEALTH ] = targ->health;
- targ->client->lastDamageTime = level.time;
- }
+
+ targ->lastDamageTime = level.time;
//TA: add to the attackers "account" on the target
if( targ->client && attacker->client )
@@ -1225,7 +1218,8 @@ qboolean G_SelectiveRadiusDamage( vec3_t origin, gentity_t *attacker, float dama
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[ 2 ] += 24;
- G_SelectiveDamage( ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod, team );
+ G_SelectiveDamage( ent, NULL, attacker, dir, origin,
+ (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod, team );
}
}
@@ -1295,7 +1289,8 @@ qboolean G_RadiusDamage( vec3_t origin, gentity_t *attacker, float damage,
// push the center of mass higher than the origin so players
// get knocked into the air more
dir[ 2 ] += 24;
- G_Damage( ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod );
+ G_Damage( ent, NULL, attacker, dir, origin,
+ (int)points, DAMAGE_RADIUS|DAMAGE_NO_LOCDAMAGE, mod );
}
}
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 4b18234f..63a4970e 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -228,6 +228,8 @@ struct gentity_s
int triggerGravity; //TA: gravity for this trigger
int suicideTime; //TA: when the client will suicide
+
+ int lastDamageTime;
};
typedef enum
@@ -322,11 +324,14 @@ typedef struct
qboolean teamInfo; // send team overlay updates?
pClass_t classSelection; //TA: player class (copied to ent->client->ps.stats[ STAT_PCLASS ] once spawned)
+ float evolveHealthFraction;
weapon_t humanItemSelection; //TA: humans have a starting item
pTeam_t teamSelection; //TA: player team (copied to ps.stats[ STAT_PTEAM ])
qboolean joinedATeam; //TA: used to tell when a PTR code is valid
connectionRecord_t *connection;
+
+ vec3_t lastDeathLocation;
} clientPersistant_t;
// this structure is cleared on each ClientSpawn(),
@@ -394,6 +399,7 @@ struct gclient_s
gentity_t *hovel; //TA: body that is being infested. must be persistant
int lastPoisonTime;
+ int poisonImmunityTime;
gentity_t *lastPoisonClient;
int lastPoisonCloudedTime;
gentity_t *lastPoisonCloudedClient;
@@ -401,8 +407,10 @@ struct gclient_s
int lastLockTime;
int lastSlowTime;
int lastBoostedTime;
+ int lastMedKitTime;
+ int medKitHealthToRestore;
+ int medKitIncrementTime;
int lastCreepSlowTime; //TA: time until creep can be removed
- int lastDamageTime;
int pouncePayload; //TA: amount of damage pounce attack will do
qboolean allowedToPounce;
@@ -433,6 +441,7 @@ typedef struct spawnQueue_s
void G_InitSpawnQueue( spawnQueue_t *sq );
int G_GetSpawnQueueLength( spawnQueue_t *sq );
int G_PopSpawnQueue( spawnQueue_t *sq );
+int G_PeekSpawnQueue( spawnQueue_t *sq );
void G_PushSpawnQueue( spawnQueue_t *sq, int clientNum );
qboolean G_RemoveFromSpawnQueue( spawnQueue_t *sq, int clientNum );
int G_GetPosInSpawnQueue( spawnQueue_t *sq, int clientNum );
@@ -694,10 +703,32 @@ void G_SetOrigin( gentity_t *ent, vec3_t origin );
void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
const char *BuildShaderStateConfig();
+#define MAX_QUEUE_COMMANDS 10
+
+typedef struct commandQueueElement_s
+{
+ qboolean used;
+ struct commandQueueElement_s *next;
+ char command[ MAX_TOKEN_CHARS ];
+} commandQueueElement_t;
+
+typedef struct commandQueue_s
+{
+ int nextCommandTime; //next time that the queue can be popped
+
+ commandQueueElement_t *front;
+ commandQueueElement_t *back;
+} commandQueue_t;
+
+void G_ProcessCommandQueues( void );
+void G_SendCommandFromServer( int clientNum, const char *cmd );
+void G_InitCommandQueue( int clientNum );
+
void G_TriggerMenu( int clientNum, dynMenu_t menu );
void G_CloseMenus( int clientNum );
qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 );
+gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities );
//
// g_combat.c
@@ -764,12 +795,44 @@ void ShineTorch( gentity_t *self );
//
// g_weapon.c
//
+
+/*typedef struct zap_s
+{
+ qboolean used;
+
+ gentity_t *creator;
+ gentity_t *source;
+ gentity_t *target;
+
+ int timeToLive;
+
+ int depth;
+
+ gentity_t *effectTempEnt;
+} zap_t;*/
+
+#define MAX_ZAP_TARGETS LEVEL2_AREAZAP_MAX_TARGETS
+
+typedef struct zap_s
+{
+ qboolean used;
+
+ gentity_t *creator;
+ gentity_t *targets[ MAX_ZAP_TARGETS ];
+ int numTargets;
+
+ int timeToLive;
+
+ gentity_t *effectChannel;
+} zap_t;
+
void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
void SnapVectorTowards( vec3_t v, vec3_t to );
qboolean CheckVenomAttack( gentity_t *ent );
void CheckGrabAttack( gentity_t *ent );
qboolean CheckPounceAttack( gentity_t *ent );
void ChargeAttack( gentity_t *ent, gentity_t *victim );
+void G_UpdateZaps( int msec );
//
@@ -778,7 +841,7 @@ void ChargeAttack( gentity_t *ent, gentity_t *victim );
void G_AddCreditToClient( gclient_t *client, short credit, qboolean cap );
team_t TeamCount( int ignoreClientNum, int team );
void SetClientViewAngle( gentity_t *ent, vec3_t angle );
-gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t origin, vec3_t angles );
+gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles );
gentity_t *SelectSpawnPoint( vec3_t avoidPoint, vec3_t origin, vec3_t angles );
void SpawnCorpse( gentity_t *ent );
void respawn( gentity_t *ent );
@@ -961,6 +1024,7 @@ extern vmCvar_t g_cheats;
extern vmCvar_t g_maxclients; // allow this many total, including spectators
extern vmCvar_t g_maxGameClients; // allow this many active
extern vmCvar_t g_restarted;
+extern vmCvar_t g_minCommandPeriod;
extern vmCvar_t g_timelimit;
extern vmCvar_t g_suddenDeathTime;
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 98566cb4..ecb56723 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -74,6 +74,7 @@ vmCvar_t pmove_fixed;
vmCvar_t pmove_msec;
vmCvar_t g_rankings;
vmCvar_t g_listEntity;
+vmCvar_t g_minCommandPeriod;
//TA
vmCvar_t g_humanBuildPoints;
@@ -154,6 +155,7 @@ static cvarTable_t gameCvarTable[ ] =
{ &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse },
{ &g_listEntity, "g_listEntity", "0", 0, 0, qfalse },
+ { &g_minCommandPeriod, "g_minCommandPeriod", "500", 0, 0, qfalse},
{ &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse},
{ &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse},
@@ -261,7 +263,7 @@ void QDECL G_Printf( const char *fmt, ... )
if( !g_dedicated.integer )
{
Com_sprintf( clientText, 1048, "gprintf \"%s\"", text );
- trap_SendServerCommand( -1, clientText );
+ G_SendCommandFromServer( -1, clientText );
}
trap_Printf( text );
@@ -403,7 +405,7 @@ void G_UpdateCvars( void )
cv->modificationCount = cv->vmCvar->modificationCount;
if( cv->trackChange )
- trap_SendServerCommand( -1, va( "print \"Server: %s changed to %s\n\"",
+ G_SendCommandFromServer( -1, va( "print \"Server: %s changed to %s\n\"",
cv->cvarName, cv->vmCvar->string ) );
if( cv->teamShader )
@@ -703,6 +705,18 @@ int G_PopSpawnQueue( spawnQueue_t *sq )
/*
============
+G_PeekSpawnQueue
+
+Look at front element from a spawn queue
+============
+*/
+int G_PeekSpawnQueue( spawnQueue_t *sq )
+{
+ return sq->clients[ sq->front ];
+}
+
+/*
+============
G_PushSpawnQueue
Add an element to the back of the spawn queue
@@ -844,7 +858,12 @@ void G_SpawnClients( pTeam_t team )
if( G_GetSpawnQueueLength( sq ) > 0 && numSpawns > 0 )
{
- if( ( spawn = SelectTremulousSpawnPoint( team, spawn_origin, spawn_angles ) ) )
+ clientNum = G_PeekSpawnQueue( sq );
+ ent = &g_entities[ clientNum ];
+
+ if( ( spawn = SelectTremulousSpawnPoint( team,
+ ent->client->pers.lastDeathLocation,
+ spawn_origin, spawn_angles ) ) )
{
clientNum = G_PopSpawnQueue( sq );
@@ -1545,6 +1564,9 @@ void CheckIntermissionExit( void )
if( cl->pers.connected != CON_CONNECTED )
continue;
+ if( cl->sess.sessionTeam == TEAM_SPECTATOR )
+ continue;
+
if( g_entities[ cl->ps.clientNum ].r.svFlags & SVF_BOT )
continue;
@@ -1649,10 +1671,13 @@ void CheckExitRules( void )
{
if( level.time - level.startTime >= g_timelimit.integer * 60000 )
{
- trap_SendServerCommand( -1, "print \"Timelimit hit\n\"" );
- G_LogPrintf( "STATS T:L A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients,
- level.averageNumHumanClients,
- s, level.time - level.startTime );
+ G_SendCommandFromServer( -1, "print \"Timelimit hit\n\"" );
+
+ G_LogPrintf( "STATS T:L A:%f H:%f M:%s D:%d AS:%d HS:%d\n",
+ level.averageNumAlienClients, level.averageNumHumanClients,
+ s, level.time - level.startTime,
+ g_alienStage.integer, g_humanStage.integer );
+
level.lastWin = PTE_NONE;
LogExit( "Timelimit hit." );
return;
@@ -1666,11 +1691,13 @@ void CheckExitRules( void )
{
//humans win
level.lastWin = PTE_HUMANS;
- trap_SendServerCommand( -1, "print \"Humans win\n\"");
- G_LogPrintf( "STATS T:H A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients,
- level.averageNumHumanClients,
- s, level.time - level.startTime );
+ G_SendCommandFromServer( -1, "print \"Humans win\n\"");
+ G_LogPrintf( "STATS T:H A:%f H:%f M:%s D:%d AS:%d HS:%d\n",
+ level.averageNumAlienClients, level.averageNumHumanClients,
+ s, level.time - level.startTime,
+ g_alienStage.integer, g_humanStage.integer );
+
LogExit( "Humans win." );
return;
}
@@ -1680,11 +1707,13 @@ void CheckExitRules( void )
{
//aliens win
level.lastWin = PTE_ALIENS;
- trap_SendServerCommand( -1, "print \"Aliens win\n\"");
- G_LogPrintf( "STATS T:A A:%f H:%f M:%s D:%d\n", level.averageNumAlienClients,
- level.averageNumHumanClients,
- s, level.time - level.startTime );
+ G_SendCommandFromServer( -1, "print \"Aliens win\n\"");
+ G_LogPrintf( "STATS T:A A:%f H:%f M:%s D:%d AS:%d HS:%d\n",
+ level.averageNumAlienClients, level.averageNumHumanClients,
+ s, level.time - level.startTime,
+ g_alienStage.integer, g_humanStage.integer );
+
LogExit( "Aliens win." );
return;
}
@@ -1733,13 +1762,13 @@ void CheckVote( void )
if( level.voteYes > level.voteNo )
{
// execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Vote passed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Vote passed\n\"" );
level.voteExecuteTime = level.time + 3000;
}
else
{
// same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Vote failed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Vote failed\n\"" );
}
}
else
@@ -1747,13 +1776,13 @@ void CheckVote( void )
if( level.voteYes > level.numConnectedClients / 2 )
{
// execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Vote passed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Vote passed\n\"" );
level.voteExecuteTime = level.time + 3000;
}
else if( level.voteNo >= level.numConnectedClients / 2 )
{
// same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Vote failed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Vote failed\n\"" );
}
else
{
@@ -1788,21 +1817,21 @@ void CheckTeamVote( int team )
if( level.time - level.teamVoteTime[ cs_offset ] >= VOTE_TIME )
{
- trap_SendServerCommand( -1, "print \"Team vote failed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Team vote failed\n\"" );
}
else
{
if( level.teamVoteYes[ cs_offset ] > level.numteamVotingClients[ cs_offset ] / 2 )
{
// execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Team vote passed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Team vote passed\n\"" );
//
trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) );
}
else if( level.teamVoteNo[ cs_offset ] >= level.numteamVotingClients[ cs_offset ] / 2 )
{
// same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Team vote failed\n\"" );
+ G_SendCommandFromServer( -1, "print \"Team vote failed\n\"" );
}
else
{
@@ -2016,7 +2045,11 @@ void G_RunFrame( int levelTime )
G_SpawnClients( PTE_ALIENS );
G_SpawnClients( PTE_HUMANS );
G_CalculateAvgPlayers( );
+ G_UpdateZaps( msec );
+ //send any pending commands
+ G_ProcessCommandQueues( );
+
// see if it is time to end the level
CheckExitRules( );
diff --git a/src/game/g_missile.c b/src/game/g_missile.c
index b1a71ac3..1d30974d 100644
--- a/src/game/g_missile.c
+++ b/src/game/g_missile.c
@@ -260,7 +260,9 @@ void G_RunMissile( gentity_t *ent )
else
VectorCopy( tr.endpos, ent->r.currentOrigin );
+ ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
trap_LinkEntity( ent );
+ ent->r.contents = 0; //...encoding bbox information
if( tr.fraction != 1 )
{
@@ -317,6 +319,8 @@ gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t dir )
bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
+ bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -15.0f;
+ bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 15.0f;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c
index c86ac2b6..0c5c3b27 100644
--- a/src/game/g_svcmds.c
+++ b/src/game/g_svcmds.c
@@ -567,12 +567,12 @@ qboolean ConsoleCommand( void )
{
if( Q_stricmp( cmd, "say" ) == 0 )
{
- trap_SendServerCommand( -1, va( "print \"server: %s\n\"", ConcatArgs( 1 ) ) );
+ G_SendCommandFromServer( -1, va( "print \"server: %s\n\"", ConcatArgs( 1 ) ) );
return qtrue;
}
// everything else will also be printed as a say command
- trap_SendServerCommand( -1, va( "print \"server: %s\n\"", ConcatArgs( 0 ) ) );
+ G_SendCommandFromServer( -1, va( "print \"server: %s\n\"", ConcatArgs( 0 ) ) );
return qtrue;
}
diff --git a/src/game/g_target.c b/src/game/g_target.c
index 64a3f33e..f57f173e 100644
--- a/src/game/g_target.c
+++ b/src/game/g_target.c
@@ -78,7 +78,7 @@ void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator )
{
if( activator->client && ( ent->spawnflags & 4 ) )
{
- trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) );
+ G_SendCommandFromServer( activator-g_entities, va( "cp \"%s\"", ent->message ) );
return;
}
@@ -92,7 +92,7 @@ void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator )
return;
}
- trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ) );
+ G_SendCommandFromServer( -1, va("cp \"%s\"", ent->message ) );
}
void SP_target_print( gentity_t *ent )
diff --git a/src/game/g_team.c b/src/game/g_team.c
index 9e0eb078..f4e035b9 100644
--- a/src/game/g_team.c
+++ b/src/game/g_team.c
@@ -34,7 +34,7 @@ void QDECL PrintMsg( gentity_t *ent, const char *fmt, ... )
while( ( p = strchr( msg, '"' ) ) != NULL )
*p = '\'';
- trap_SendServerCommand( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) );
+ G_SendCommandFromServer( ( ( ent == NULL ) ? -1 : ent-g_entities ), va( "print \"%s\"", msg ) );
}
@@ -204,7 +204,7 @@ void TeamplayInfoMessage( gentity_t *ent )
}
}
- trap_SendServerCommand( ent - g_entities, va( "tinfo %i %s", cnt, string ) );
+ G_SendCommandFromServer( ent - g_entities, va( "tinfo %i %s", cnt, string ) );
}
void CheckTeamStatus( void )
diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c
index fbcf4c4f..aff816dc 100644
--- a/src/game/g_trigger.c
+++ b/src/game/g_trigger.c
@@ -1111,9 +1111,9 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
else
self->timestamp = level.time + FRAMETIME;
- BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, NULL, NULL );
+ BG_FindAmmoForWeapon( other->client->ps.weapon, &maxAmmo, &maxClips );
BG_UnpackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups,
- &ammo, &clips, &maxClips );
+ &ammo, &clips );
if( ( ammo + self->damage ) > maxAmmo )
{
@@ -1129,7 +1129,7 @@ void trigger_ammo_touch( gentity_t *self, gentity_t *other, trace_t *trace )
ammo += self->damage;
BG_PackAmmoArray( other->client->ps.weapon, other->client->ps.ammo, other->client->ps.powerups,
- ammo, clips, maxClips );
+ ammo, clips );
}
/*
diff --git a/src/game/g_utils.c b/src/game/g_utils.c
index 95e117d2..b09ec8cb 100644
--- a/src/game/g_utils.c
+++ b/src/game/g_utils.c
@@ -155,7 +155,7 @@ void G_TeamCommand( pTeam_t team, char *cmd )
if( level.clients[ i ].pers.connected == CON_CONNECTED )
{
if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
- trap_SendServerCommand( i, va( "%s", cmd ) );
+ G_SendCommandFromServer( i, va( "%s", cmd ) );
}
}
}
@@ -683,6 +683,195 @@ void G_Sound( gentity_t *ent, int channel, int soundIndex )
}
+#define MAX_QUEUE_ELEMENTS MAX_CLIENTS * MAX_QUEUE_COMMANDS
+
+static commandQueueElement_t queuedCommandElements[ MAX_QUEUE_ELEMENTS ];
+static commandQueue_t queuedCommands[ MAX_CLIENTS ];
+
+/*
+===============
+G_PopCommandQueue
+
+Return the front of a command queue
+Must use immediately or copy to a buffer
+===============
+*/
+static const char *G_PopCommandQueue( commandQueue_t *cq )
+{
+ if( cq->front )
+ {
+ commandQueueElement_t *cqe = cq->front;
+
+ cq->front = cqe->next;
+
+ // last element in the queue
+ if( cq->front == NULL )
+ cq->back = NULL;
+
+ cq->nextCommandTime = level.time + g_minCommandPeriod.integer;
+ cqe->used = qfalse;
+
+ return cqe->command;
+ }
+ else
+ return NULL;
+}
+
+/*
+===============
+G_PushCommandQueue
+
+Put a command on a command queue
+===============
+*/
+static void G_PushCommandQueue( commandQueue_t *cq, const char *cmd )
+{
+ int i;
+
+ for( i = 0; i < MAX_QUEUE_ELEMENTS; i++ )
+ {
+ commandQueueElement_t *cqe = &queuedCommandElements[ i ];
+
+ if( !cqe->used )
+ {
+ cqe->used = qtrue;
+ cqe->next = NULL;
+ Q_strncpyz( cqe->command, cmd, MAX_TOKEN_CHARS );
+
+ if( cq->back )
+ {
+ cq->back->next = cqe;
+ cq->back = cqe;
+ }
+ else
+ {
+ cq->front = cqe;
+ cq->back = cqe;
+ }
+
+ return;
+ }
+ }
+
+ //drop the command
+}
+
+/*
+===============
+G_PrintCommandQueue
+===============
+*/
+#if 0 //quiet compiler
+static void G_PrintCommandQueue( commandQueue_t *cq )
+{
+ commandQueueElement_t *cqe;
+
+ if( cq->front )
+ {
+ cqe = cq->front;
+
+ do
+ {
+ G_Printf( "->\"%s\"", cqe->command );
+ } while( ( cqe = cqe->next ) );
+
+ G_Printf( "\n" );
+ }
+}
+#endif
+
+/*
+===============
+G_ReadyToDequeue
+===============
+*/
+static qboolean G_ReadyToDequeue( commandQueue_t *cq )
+{
+ if( !cq )
+ return qfalse;
+
+ return cq->front && cq->nextCommandTime <= level.time;
+}
+
+/*
+===============
+G_ProcessCommandQueues
+
+Check for any outstanding commands to be sent
+===============
+*/
+void G_ProcessCommandQueues( void )
+{
+ int i;
+
+ for( i = 0; i < MAX_CLIENTS; i++ )
+ {
+ commandQueue_t *cq = &queuedCommands[ i ];
+
+ if( G_ReadyToDequeue( cq ) )
+ {
+ const char *command = G_PopCommandQueue( cq );
+
+ if( command )
+ trap_SendServerCommand( i, command );
+ }
+ }
+}
+
+/*
+===============
+G_InitCommandQueue
+===============
+*/
+void G_InitCommandQueue( int clientNum )
+{
+ commandQueue_t *cq = &queuedCommands[ clientNum ];
+
+ if( clientNum >= 0 && clientNum < MAX_CLIENTS )
+ {
+ cq->front = cq->back = NULL;
+ cq->nextCommandTime = 0;
+ }
+}
+
+/*
+===============
+G_SendCommandFromServer
+
+Sends a command to a client
+===============
+*/
+void G_SendCommandFromServer( int clientNum, const char *cmd )
+{
+ commandQueue_t *cq = &queuedCommands[ clientNum ];
+
+ if( clientNum < 0 )
+ cq = NULL;
+
+ if( strlen( cmd ) > 1022 )
+ {
+ G_LogPrintf( "G_SendCommandFromServer( %d, ... ) length exceeds 1022.\n", clientNum );
+ G_LogPrintf( "cmd [%s]\n", cmd );
+ return;
+ }
+
+ if( cq )
+ {
+ if( cq->nextCommandTime > level.time )
+ {
+ //can't send yet, so queue the command up
+ G_PushCommandQueue( cq, cmd );
+ }
+ else
+ {
+ cq->nextCommandTime = level.time + g_minCommandPeriod.integer;
+ trap_SendServerCommand( clientNum, cmd );
+ }
+ }
+ else
+ trap_SendServerCommand( clientNum, cmd );
+}
+
//==============================================================================
@@ -735,8 +924,13 @@ gentity_t *G_FindRadius( gentity_t *from, vec3_t org, float rad )
return NULL;
}
-// (NOBODY): Code helper function
-//
+/*
+===============
+G_Visible
+
+Test for a LOS between two entities
+===============
+*/
qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 )
{
trace_t trace;
@@ -749,6 +943,32 @@ qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 )
return qtrue;
}
+/*
+===============
+G_ClosestEnt
+
+Test a list of entities for the closest to a particular point
+===============
+*/
+gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities )
+{
+ int i;
+ float nd, d = 1000000.0f;
+ gentity_t *closestEnt = NULL;
+
+ for( i = 0; i < numEntities; i++ )
+ {
+ gentity_t *ent = entities[ i ];
+
+ if( ( nd = VectorDistance( origin, ent->s.origin ) ) < d )
+ {
+ d = nd;
+ closestEnt = ent;
+ }
+ }
+
+ return closestEnt;
+}
/*
===============
@@ -762,7 +982,7 @@ void G_TriggerMenu( int clientNum, dynMenu_t menu )
char buffer[ 32 ];
Com_sprintf( buffer, 32, "servermenu %d", menu );
- trap_SendServerCommand( clientNum, buffer );
+ G_SendCommandFromServer( clientNum, buffer );
}
@@ -778,7 +998,7 @@ void G_CloseMenus( int clientNum )
char buffer[ 32 ];
Com_sprintf( buffer, 32, "serverclosemenus" );
- trap_SendServerCommand( clientNum, buffer );
+ G_SendCommandFromServer( clientNum, buffer );
}
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c
index 7094bcdb..1dbd5c15 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -871,7 +871,7 @@ void poisonCloud( gentity_t *ent )
humanPlayer->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED;
humanPlayer->client->lastPoisonCloudedTime = level.time;
humanPlayer->client->lastPoisonCloudedClient = ent;
- trap_SendServerCommand( humanPlayer->client->ps.clientNum, "poisoncloud" );
+ G_SendCommandFromServer( humanPlayer->client->ps.clientNum, "poisoncloud" );
}
}
}
@@ -886,25 +886,27 @@ LEVEL2
======================================================================
*/
+#define MAX_ZAPS 64
+
+static zap_t zaps[ MAX_CLIENTS ];
+
/*
===============
-areaZapFire
+G_FindNewZapTarget
===============
*/
-void areaZapFire( gentity_t *ent )
+static gentity_t *G_FindNewZapTarget( gentity_t *ent )
{
int entityList[ MAX_GENTITIES ];
- int targetList[ MAX_GENTITIES ];
vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE };
- vec3_t mins, maxs, dir;
- int i, num, numTargets = 0;
+ vec3_t mins, maxs;
+ int i, j, k, num;
gentity_t *enemy;
- gentity_t *tent;
trace_t tr;
- int damage;
- VectorAdd( ent->client->ps.origin, range, maxs );
- VectorSubtract( ent->client->ps.origin, range, mins );
+ VectorScale( range, 1.0f / M_ROOT3, range );
+ VectorAdd( ent->s.origin, range, maxs );
+ VectorSubtract( ent->s.origin, range, mins );
num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
@@ -912,41 +914,227 @@ void areaZapFire( gentity_t *ent )
{
enemy = &g_entities[ entityList[ i ] ];
- if( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
- ( enemy->s.eType == ET_BUILDABLE && BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) )
+ if( ( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
+ ( enemy->s.eType == ET_BUILDABLE &&
+ BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) && enemy->health > 0 )
{
+ qboolean foundOldTarget = qfalse;
+
trap_Trace( &tr, muzzle, NULL, NULL, enemy->s.origin, ent->s.number, MASK_SHOT );
//can't see target from here
if( tr.entityNum == ENTITYNUM_WORLD )
continue;
- targetList[ numTargets++ ] = entityList[ i ];
+ for( j = 0; j < MAX_ZAPS; j++ )
+ {
+ zap_t *zap = &zaps[ j ];
+
+ for( k = 0; k < zap->numTargets; k++ )
+ {
+ if( zap->targets[ k ] == enemy )
+ {
+ foundOldTarget = qtrue;
+ break;
+ }
+ }
+
+ if( foundOldTarget )
+ break;
+ }
+
+ // enemy is already targetted
+ if( foundOldTarget )
+ continue;
+
+ return enemy;
}
}
- damage = (int)( (float)LEVEL2_AREAZAP_DMG / (float)numTargets );
- for( i = 0; i < numTargets; i++ )
- {
- enemy = &g_entities[ targetList[ i ] ];
+ return NULL;
+}
- VectorSubtract( enemy->s.origin, muzzle, dir );
- VectorNormalize( dir );
-
- //do some damage
- G_Damage( enemy, ent, ent, dir, tr.endpos,
- damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP );
+/*
+===============
+G_UpdateZapEffect
+===============
+*/
+static void G_UpdateZapEffect( zap_t *zap )
+{
+ int j;
+ gentity_t *effect = zap->effectChannel;
+
+ effect->s.eType = ET_LEV2_ZAP_CHAIN;
+ effect->classname = "lev2zapchain";
+ G_SetOrigin( effect, zap->creator->s.origin );
+ effect->s.powerups = zap->creator->s.number;
+
+ effect->s.time = effect->s.time2 = effect->s.constantLight = -1;
+
+ for( j = 0; j < zap->numTargets; j++ )
+ {
+ int number = zap->targets[ j ]->s.number;
- // snap the endpos to integers to save net bandwidth, but nudged towards the line
- SnapVectorTowards( tr.endpos, muzzle );
+ switch( j )
+ {
+ case 0: effect->s.time = number; break;
+ case 1: effect->s.time2 = number; break;
+ case 2: effect->s.constantLight = number; break;
+ default: break;
+ }
+ }
+
+ trap_LinkEntity( effect );
+}
+
+/*
+===============
+G_CreateNewZap
+===============
+*/
+static void G_CreateNewZap( gentity_t *creator, gentity_t *target )
+{
+ int i, j;
+ zap_t *zap;
+
+ for( i = 0; i < MAX_ZAPS; i++ )
+ {
+ zap = &zaps[ i ];
+
+ if( !zap->used )
+ {
+ zap->used = qtrue;
+
+ zap->timeToLive = LEVEL2_AREAZAP_TIME;
+
+ zap->creator = creator;
+
+ zap->targets[ 0 ] = target;
+ zap->numTargets = 1;
+
+ for( j = 1; j < MAX_ZAP_TARGETS && zap->targets[ j - 1 ]; j++ )
+ {
+ zap->targets[ j ] = G_FindNewZapTarget( zap->targets[ j - 1 ] );
+
+ if( zap->targets[ j ] )
+ zap->numTargets++;
+ }
+
+ zap->effectChannel = G_Spawn( );
+ G_UpdateZapEffect( zap );
+
+ return;
+ }
+ }
+}
+
+
+/*
+===============
+G_UpdateZaps
+===============
+*/
+void G_UpdateZaps( int msec )
+{
+ int i, j;
+ zap_t *zap;
+ int damage;
+
+ for( i = 0; i < MAX_ZAPS; i++ )
+ {
+ zap = &zaps[ i ];
+
+ if( zap->used )
+ {
+ //check each target is valid
+ for( j = 0; j < zap->numTargets; j++ )
+ {
+ gentity_t *source;
+ gentity_t *target = zap->targets[ j ];
+
+ if( j == 0 )
+ source = zap->creator;
+ else
+ source = zap->targets[ j - 1 ];
+
+ if( target->health <= 0 || !target->inuse || //early out
+ VectorDistance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
+ {
+ target = zap->targets[ j ] = G_FindNewZapTarget( source );
+
+ //couldn't find a target, so forget about the rest of the chain
+ if( !target )
+ zap->numTargets = j;
+ }
+
+ }
+
+ if( zap->numTargets )
+ {
+ for( j = 0; j < zap->numTargets; j++ )
+ {
+ gentity_t *source;
+ gentity_t *target = zap->targets[ j ];
+ float r = 1.0f / zap->numTargets;
+ float damageFraction = 2 * r - 2 * j * r * r - r * r;
+
+ if( j == 0 )
+ source = zap->creator;
+ else
+ source = zap->targets[ j - 1 ];
+
+ damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) *
+ LEVEL2_AREAZAP_DMG * damageFraction );
+
+ //do the damage
+ if( damage )
+ G_Damage( target, source, zap->creator, NULL, NULL,
+ damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP );
+ }
+ }
+
+ G_UpdateZapEffect( zap );
+
+ zap->timeToLive -= msec;
+
+ if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 )
+ {
+ zap->used = qfalse;
+ G_FreeEntity( zap->effectChannel );
+ }
+ }
+ }
+}
- // send arc effect
- tent = G_TempEntity( enemy->s.pos.trBase, EV_ALIENZAP );
+/*
+===============
+areaZapFire
+===============
+*/
+void areaZapFire( gentity_t *ent )
+{
+ trace_t tr;
+ vec3_t end;
+ gentity_t *traceEnt;
- VectorCopy( ent->client->ps.origin, tent->s.origin2 );
+ // set aiming directions
+ AngleVectors( ent->client->ps.viewangles, forward, right, up );
+
+ CalcMuzzlePoint( ent, forward, right, up, muzzle );
+
+ VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end );
+
+ trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT );
+ if( tr.surfaceFlags & SURF_NOIMPACT )
+ return;
- tent->s.generic1 = ent->s.number; //src
- tent->s.clientNum = enemy->s.number; //dest
+ traceEnt = &g_entities[ tr.entityNum ];
+
+ if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ||
+ ( traceEnt->s.eType == ET_BUILDABLE &&
+ BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 )
+ {
+ G_CreateNewZap( ent, traceEnt );
}
}
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index ce0fbff4..98fb60de 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -64,6 +64,8 @@
#define LEVEL2_AREAZAP_DMG ADM(80)
#define LEVEL2_AREAZAP_RANGE 200.0f
#define LEVEL2_AREAZAP_REPEAT 3000
+#define LEVEL2_AREAZAP_TIME 1000
+#define LEVEL2_AREAZAP_MAX_TARGETS 3
#define LEVEL2_WALLJUMP_MAXSPEED 1000.0f
#define LEVEL3_CLAW_DMG ADM(80)
@@ -78,11 +80,11 @@
#define LEVEL3_POUNCE_UPG_SPEED 800
#define LEVEL3_POUNCE_SPEED_MOD 0.75f
#define LEVEL3_POUNCE_TIME 700
-#define LEVEL3_BOUNCEBALL_DMG ADM(120)
+#define LEVEL3_BOUNCEBALL_DMG ADM(110)
#define LEVEL3_BOUNCEBALL_REPEAT 1000
#define LEVEL3_BOUNCEBALL_SPEED 1000.0f
-#define LEVEL4_CLAW_DMG ADM(120)
+#define LEVEL4_CLAW_DMG ADM(100)
#define LEVEL4_CLAW_RANGE 128.0f
#define LEVEL4_CLAW_WIDTH 20.0f
#define LEVEL4_CLAW_REPEAT 750
@@ -90,10 +92,11 @@
#define LEVEL4_REGEN_MOD 2.0f
#define LEVEL4_CHARGE_SPEED 2.0f
#define LEVEL4_CHARGE_TIME 3000
-#define LEVEL4_CHARGE_CHARGE_TIME 1000
+#define LEVEL4_CHARGE_CHARGE_TIME 1500
+#define LEVEL4_MIN_CHARGE_TIME 750
#define LEVEL4_CHARGE_CHARGE_RATIO (LEVEL4_CHARGE_TIME/LEVEL4_CHARGE_CHARGE_TIME)
-#define LEVEL4_CHARGE_REPEAT 500
-#define LEVEL4_CHARGE_DMG ADM(160)
+#define LEVEL4_CHARGE_REPEAT 1000
+#define LEVEL4_CHARGE_DMG ADM(110)
@@ -210,7 +213,7 @@
#define BARRICADE_BP 10
#define BARRICADE_BT 20000
#define BARRICADE_HEALTH ABHM(200)
-#define BARRICADE_REGEN 12
+#define BARRICADE_REGEN 14
#define BARRICADE_SPLASHDAMAGE 50
#define BARRICADE_SPLASHRADIUS 50
#define BARRICADE_CREEPSIZE 120
@@ -229,7 +232,7 @@
#define ACIDTUBE_BT 15000
#define ACIDTUBE_HEALTH ABHM(125)
#define ACIDTUBE_REGEN 10
-#define ACIDTUBE_SPLASHDAMAGE 30
+#define ACIDTUBE_SPLASHDAMAGE 6
#define ACIDTUBE_SPLASHRADIUS 300
#define ACIDTUBE_CREEPSIZE 120
#define ACIDTUBE_RANGE 300.0f
@@ -262,8 +265,8 @@
#define OVERMIND_BP 0
#define OVERMIND_BT 30000
-#define OVERMIND_HEALTH ABHM(500)
-#define OVERMIND_REGEN 10
+#define OVERMIND_HEALTH ABHM(750)
+#define OVERMIND_REGEN 6
#define OVERMIND_SPLASHDAMAGE 15
#define OVERMIND_SPLASHRADIUS 300
#define OVERMIND_CREEPSIZE 120
@@ -314,12 +317,11 @@
#define BLASTER_REPEAT 600
#define BLASTER_SPREAD 200
-#define BLASTER_SPEED 700
+#define BLASTER_SPEED 1400
#define BLASTER_DMG HDM(9)
#define RIFLE_CLIPSIZE 30
-#define RIFLE_SPAWNCLIPS 4
-#define RIFLE_MAXCLIPS 4
+#define RIFLE_MAXCLIPS 6
#define RIFLE_REPEAT 90
#define RIFLE_RELOAD 2000
#define RIFLE_PRICE 0
@@ -328,10 +330,10 @@
#define PAINSAW_PRICE 100
#define PAINSAW_REPEAT 75
-#define PAINSAW_DAMAGE HDM(18)
-#define PAINSAW_RANGE 48.0f
+#define PAINSAW_DAMAGE HDM(15)
+#define PAINSAW_RANGE 40.0f
-#define GRENADE_PRICE 300
+#define GRENADE_PRICE 200
#define GRENADE_REPEAT 0
#define GRENADE_DAMAGE HDM(310)
#define GRENADE_RANGE 192.0f
@@ -340,53 +342,50 @@
#define SHOTGUN_PRICE 150
#define SHOTGUN_SHELLS 8
#define SHOTGUN_PELLETS 8 //used to sync server and client side
-#define SHOTGUN_SPAWNCLIPS 2
-#define SHOTGUN_MAXCLIPS 2
-#define SHOTGUN_REPEAT 1200
+#define SHOTGUN_MAXCLIPS 3
+#define SHOTGUN_REPEAT 1000
#define SHOTGUN_RELOAD 2000
#define SHOTGUN_SPREAD 900
-#define SHOTGUN_DMG HDM(6)
+#define SHOTGUN_DMG HDM(7)
#define LASGUN_PRICE 250
-#define LASGUN_AMMO 150
+#define LASGUN_AMMO 200
#define LASGUN_REPEAT 200
#define LASGUN_RELOAD 2000
#define LASGUN_DAMAGE HDM(9)
#define MDRIVER_PRICE 350
#define MDRIVER_CLIPSIZE 5
-#define MDRIVER_SPAWNCLIPS 3
-#define MDRIVER_MAXCLIPS 3
-#define MDRIVER_DMG HDM(35)
+#define MDRIVER_MAXCLIPS 4
+#define MDRIVER_DMG HDM(38)
#define MDRIVER_REPEAT 1000
#define MDRIVER_RELOAD 2000
#define CHAINGUN_PRICE 400
-#define CHAINGUN_BULLETS 200
+#define CHAINGUN_BULLETS 300
#define CHAINGUN_REPEAT 80
#define CHAINGUN_SPREAD 1000
-#define CHAINGUN_DMG HDM(5)
+#define CHAINGUN_DMG HDM(6)
#define PRIFLE_PRICE 400
#define PRIFLE_CLIPS 50
-#define PRIFLE_SPAWNCLIPS 2
-#define PRIFLE_MAXCLIPS 2
+#define PRIFLE_MAXCLIPS 4
#define PRIFLE_REPEAT 100
#define PRIFLE_RELOAD 2000
#define PRIFLE_DMG HDM(9)
#define PRIFLE_SPEED 1000
#define FLAMER_PRICE 450
-#define FLAMER_GAS 80
-#define FLAMER_REPEAT 300
+#define FLAMER_GAS 150
+#define FLAMER_REPEAT 200
#define FLAMER_DMG HDM(31)
#define FLAMER_RADIUS 50
-#define FLAMER_LIFETIME 500.0f
+#define FLAMER_LIFETIME 800.0f
#define FLAMER_SPEED 200.0f
#define FLAMER_LAG 0.65f //the amount of player velocity that is added to the fireball
#define LCANNON_PRICE 600
-#define LCANNON_AMMO 60
+#define LCANNON_AMMO 90
#define LCANNON_REPEAT 500
#define LCANNON_CHARGEREPEAT 1000
#define LCANNON_RELOAD 2000
@@ -418,7 +417,7 @@
#define HELMET_PRICE 90
#define HELMET_RANGE 1000.0f
-#define ANTITOXIN_PRICE 20
+#define MEDKIT_PRICE 0
#define BATTPACK_PRICE 100
#define BATTPACK_MODIFIER 1.5f //modifier for extra energy storage available
@@ -437,6 +436,9 @@
#define GAS_PRICE 0
+#define MEDKIT_POISON_IMMUNITY_TIME 30000
+#define MEDKIT_STARTUP_TIME 4000
+#define MEDKIT_STARTUP_SPEED 5
/*
@@ -476,8 +478,8 @@
#define MGTURRET_BP 8
#define MGTURRET_BT 10000
#define MGTURRET_HEALTH HBHM(190)
-#define MGTURRET_SPLASHDAMAGE 200
-#define MGTURRET_SPLASHRADIUS 150
+#define MGTURRET_SPLASHDAMAGE 100
+#define MGTURRET_SPLASHRADIUS 100
#define MGTURRET_ANGULARSPEED 8 //degrees/think ~= 200deg/sec
#define MGTURRET_ACCURACYTOLERANCE MGTURRET_ANGULARSPEED / 1.5f //angular difference for turret to fire
#define MGTURRET_VERTICALCAP 30 // +/- maximum pitch
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index 200b8b8a..34f77c91 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -3445,6 +3445,7 @@ static void UI_LoadTremHumanArmouryBuys( )
for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ )
{
if( BG_FindTeamForUpgrade( i ) == WUT_HUMANS &&
+ BG_FindPurchasableForUpgrade( i ) &&
BG_FindStagesForUpgrade( i, stage ) &&
!( BG_FindSlotsForUpgrade( i ) & slots ) &&
!( upgrades & ( 1 << i ) ) )
diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c
index 06ba8cde..8d019150 100644
--- a/src/ui/ui_shared.c
+++ b/src/ui/ui_shared.c
@@ -3410,6 +3410,7 @@ static bind_t g_bindings[] =
{ "+button5", K_MOUSE2, -1, -1, -1 }, //TA: secondary attack
{ "reload", 'r', -1, -1, -1 }, //TA: reload
{ "buy ammo", 'b', -1, -1, -1 }, //TA: buy ammo
+ { "itemact medkit", 'm', -1, -1, -1 }, //TA: use medkit
{ "+button7", 'q', -1, -1, -1 }, //TA: buildable use
{ "deconstruct", 'e', -1, -1, -1 }, //TA: buildable destroy
{ "weapprev", '[', -1, -1, -1 },