summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cgame/cg_draw.c73
-rw-r--r--src/cgame/cg_tutorial.c11
-rw-r--r--src/cgame/cg_view.c12
-rw-r--r--src/game/bg_pmove.c62
-rw-r--r--src/game/bg_public.h3
-rw-r--r--src/game/g_active.c22
-rw-r--r--src/game/g_buildable.c9
-rw-r--r--src/game/g_client.c2
-rw-r--r--src/game/g_cmds.c5
-rw-r--r--src/game/tremulous.h14
10 files changed, 207 insertions, 6 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index 570276b..0af9839 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -375,10 +375,34 @@ static void CG_DrawPlayerStamina( int ownerDraw, rectDef_t *rect,
vec4_t backColor, vec4_t foreColor,
qhandle_t shader )
{
+ playerState_t *ps = &cg.snap->ps;
+ float stamina = ps->stats[ STAT_STAMINA ];
+ float maxStaminaBy3 = (float)STAMINA_MAX / 3.0f;
float progress;
vec4_t color;
- progress = 0.0f;
+ switch( ownerDraw )
+ {
+ case CG_PLAYER_STAMINA_1:
+ progress = ( stamina - 2 * (int)maxStaminaBy3 ) / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_2:
+ progress = ( stamina - (int)maxStaminaBy3 ) / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_3:
+ progress = stamina / maxStaminaBy3;
+ break;
+ case CG_PLAYER_STAMINA_4:
+ progress = ( stamina + STAMINA_MAX ) / STAMINA_MAX;
+ break;
+ default:
+ return;
+ }
+
+ if( progress > 1.0f )
+ progress = 1.0f;
+ else if( progress < 0.0f )
+ progress = 0.0f;
Vector4Lerp( progress, backColor, foreColor, color );
@@ -395,9 +419,25 @@ CG_DrawPlayerStaminaBolt
static void CG_DrawPlayerStaminaBolt( rectDef_t *rect, vec4_t backColor,
vec4_t foreColor, qhandle_t shader )
{
+ float stamina = cg.snap->ps.stats[ STAT_STAMINA ];
vec4_t color;
- Vector4Copy( backColor, color );
+ if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_SPEEDBOOST )
+ {
+ if( stamina >= 0 )
+ Vector4Lerp( ( sin( cg.time / 150.0f ) + 1 ) / 2,
+ backColor, foreColor, color );
+ else
+ Vector4Lerp( ( sin( cg.time / 2000.0f ) + 1 ) / 2,
+ backColor, foreColor, color );
+ }
+ else
+ {
+ if( stamina < 0 )
+ Vector4Copy( backColor, color );
+ else
+ Vector4Copy( foreColor, color );
+ }
trap_R_SetColor( color );
CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader );
@@ -3420,6 +3460,31 @@ void CG_RunMenuScript( char **args )
}
//END TA UI
+
+/*
+================
+CG_DrawLighting
+
+================
+*/
+static void CG_DrawLighting( void )
+{
+ // centity_t *cent;
+
+ // cent = &cg_entities[ cg.snap->ps.clientNum ];
+
+ //fade to black if stamina is low
+ if( ( cg.snap->ps.stats[ STAT_STAMINA ] < STAMINA_BLACKOUT_LEVEL ) &&
+ ( cg.snap->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) )
+ {
+ vec4_t black = { 0, 0, 0, 0 };
+ black[ 3 ] = 1.0 - ( (float)( cg.snap->ps.stats[ STAT_STAMINA ] + 1000 ) / 200.0f );
+ trap_R_SetColor( black );
+ CG_DrawPic( 0, 0, 640, 480, cgs.media.whiteShader );
+ trap_R_SetColor( NULL );
+ }
+}
+
/*
===============================================================================
@@ -4097,6 +4162,10 @@ static void CG_Draw2D( void )
if( cg.levelShot )
return;
+ // fading to black if stamina runs out
+ // (only 2D that can't be disabled)
+ CG_DrawLighting( );
+
if( cg_draw2D.integer == 0 )
return;
diff --git a/src/cgame/cg_tutorial.c b/src/cgame/cg_tutorial.c
index d2f01b3..d36ecac 100644
--- a/src/cgame/cg_tutorial.c
+++ b/src/cgame/cg_tutorial.c
@@ -514,6 +514,17 @@ static void CG_HumanText( char *text, playerState_t *ps )
BG_Upgrade( UP_MEDKIT )->humanName ) );
}
+ if( ps->stats[ STAT_STAMINA ] <= STAMINA_BLACKOUT_LEVEL )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ "You are blacking out. Stop sprinting to recover stamina\n" );
+ }
+ else if( ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ "Your stamina is low. Stop sprinting to recover\n" );
+ }
+
switch( cg.nearUsableBuildable )
{
case BA_H_ARMOURY:
diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c
index 333e421..1221fe9 100644
--- a/src/cgame/cg_view.c
+++ b/src/cgame/cg_view.c
@@ -809,6 +809,18 @@ void CG_OffsetFirstPersonView( void )
cg.predictedPlayerState.pm_type == PM_JETPACK ) )
{
angles[PITCH] += cg.bobfracsin * bob2 * 0.5;
+
+ // heavy breathing effects //FIXME: sound
+ if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < STAMINA_BREATHING_LEVEL )
+ {
+ float deltaBreath = ( cg.predictedPlayerState.stats[ STAT_STAMINA ] -
+ STAMINA_BREATHING_LEVEL ) / -250.0;
+ float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath;
+
+ deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5;
+
+ angles[ PITCH ] -= deltaAngle;
+ }
}
//===================================
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
index 63b67fa..ecdaccf 100644
--- a/src/game/bg_pmove.c
+++ b/src/game/bg_pmove.c
@@ -406,6 +406,57 @@ static float PM_CmdScale( usercmd_t *cmd )
if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS && pm->ps->pm_type == PM_NORMAL )
{
+ qboolean wasSprinting;
+ qboolean sprint;
+ wasSprinting = sprint = pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST;
+
+ if( pm->ps->persistant[ PERS_STATE ] & PS_SPRINTTOGGLE )
+ {
+ if( cmd->buttons & BUTTON_SPRINT &&
+ !( pm->ps->pm_flags & PMF_SPRINTHELD ) )
+ {
+ sprint = !sprint;
+ pm->ps->pm_flags |= PMF_SPRINTHELD;
+ }
+ else if( pm->ps->pm_flags & PMF_SPRINTHELD &&
+ !( cmd->buttons & BUTTON_SPRINT ) )
+ pm->ps->pm_flags &= ~PMF_SPRINTHELD;
+ }
+ else
+ sprint = cmd->buttons & BUTTON_SPRINT;
+
+ if( sprint )
+ pm->ps->stats[ STAT_STATE ] |= SS_SPEEDBOOST;
+ else if( wasSprinting && !sprint )
+ pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
+
+ // Walk overrides sprint. We keep the state that we want to be sprinting
+ // (above), but don't apply the modifier, and in g_active we skip taking
+ // the stamina too.
+ if( sprint && !( cmd->buttons & BUTTON_WALKING ) )
+ modifier *= HUMAN_SPRINT_MODIFIER;
+ else
+ modifier *= HUMAN_JOG_MODIFIER;
+
+ if( cmd->forwardmove < 0 )
+ {
+ //can't run backwards
+ modifier *= HUMAN_BACK_MODIFIER;
+ }
+ else if( cmd->rightmove )
+ {
+ //can't move that fast sideways
+ modifier *= HUMAN_SIDE_MODIFIER;
+ }
+
+ //must have have stamina to jump
+ if( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE )
+ cmd->upmove = 0;
+
+ //slow down once stamina depletes
+ if( pm->ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL )
+ modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + STAMINA_MAX ) / (float)(STAMINA_SLOW_LEVEL + STAMINA_MAX);
+
if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED )
{
if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, pm->ps->stats ) ||
@@ -906,6 +957,10 @@ static qboolean PM_CheckJump( void )
pm->ps->stats[ STAT_MISC ] > 0 )
return qfalse;
+ if( ( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS ) &&
+ ( pm->ps->stats[ STAT_STAMINA ] < STAMINA_SLOW_LEVEL + STAMINA_JUMP_TAKE ) )
+ return qfalse;
+
//no bunny hopping off a dodge
if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS &&
pm->ps->pm_time )
@@ -944,6 +999,10 @@ static qboolean PM_CheckJump( void )
pml.walking = qfalse;
pm->ps->pm_flags |= PMF_JUMP_HELD;
+ // take some stamina off
+ if( pm->ps->stats[ STAT_TEAM ] == TEAM_HUMANS )
+ pm->ps->stats[ STAT_STAMINA ] -= STAMINA_JUMP_TAKE;
+
pm->ps->groundEntityNum = ENTITYNUM_NONE;
// jump away from wall
@@ -2748,6 +2807,9 @@ static void PM_Footsteps( void )
bobmove *= BG_Class( pm->ps->stats[ STAT_CLASS ] )->bobCycle;
+ if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST )
+ bobmove *= HUMAN_SPRINT_MODIFIER;
+
// check for footstep / splash sounds
old = pm->ps->bobCycle;
pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 61da2f7..1e9d23c 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -224,12 +224,13 @@ typedef enum
STAT_MAX_HEALTH,// health / armor limit, changable by handicap
STAT_CLASS, // player class (for aliens AND humans)
STAT_TEAM, // player team
+ STAT_STAMINA, // stamina (human only)
STAT_STATE, // client states e.g. wall climbing
STAT_MISC, // for uh...misc stuff (pounce, trample, lcannon)
STAT_BUILDABLE, // which ghost model to display for building
STAT_FALLDIST, // the distance the player fell
STAT_VIEWLOCK // direction to lock the view in
- // netcode has space for 4 more
+ // netcode has space for 3 more
} statIndex_t;
#define SCA_WALLCLIMBER 0x00000001
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 2bf6400..0c84f57 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -631,6 +631,7 @@ void SpectatorThink( gentity_t *ent, usercmd_t *ucmd )
client->ps.pm_flags |= PMF_QUEUED;
client->ps.speed = client->pers.flySpeed;
+ client->ps.stats[ STAT_STAMINA ] = 0;
client->ps.stats[ STAT_MISC ] = 0;
client->ps.stats[ STAT_BUILDABLE ] = BA_NONE;
client->ps.stats[ STAT_CLASS ] = PCL_NONE;
@@ -806,10 +807,26 @@ void ClientTimerActions( gentity_t *ent, int msec )
client->ps.stats[ STAT_STATE ] &= ~SS_INVI;
}
- // Regenerate health if we have got a Biokit
+ // Restore or subtract stamina
+ if( stopped || client->ps.pm_type == PM_JETPACK )
+ client->ps.stats[ STAT_STAMINA ] += STAMINA_STOP_RESTORE;
+ else if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) &&
+ !( client->buttons & BUTTON_WALKING ) ) // walk overrides sprint
+ client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE;
+ else if( walking || crouched )
+ client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE;
+
+ // Check stamina limits
+ if( client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+ else if( client->ps.stats[ STAT_STAMINA ] < -STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] = -STAMINA_MAX;
+
+ // Regenerate health and stamina if we have got a Biokit
if( BG_InventoryContainsUpgrade( UP_BIOKIT, client->ps.stats ) )
{
int rate_health = BIOKIT_HEALTH_RATE;
+ int rate_stamina = BIOKIT_STAMINA_RATE;
if( ent->nextRegenTime < level.time && ent->health > 0 && rate_health > 0 &&
ent->health < client->ps.stats[ STAT_MAX_HEALTH ] )
@@ -823,6 +840,9 @@ void ClientTimerActions( gentity_t *ent, int msec )
ent->nextRegenTime = level.time + 5000/rate_health;
ent->client->alreadyRegenerated = qtrue;
}
+
+ if( client->ps.stats[ STAT_STAMINA ] + rate_stamina <= STAMINA_MAX )
+ client->ps.stats[ STAT_STAMINA ] += rate_stamina;
}
if( weapon == WP_ABUILD ||
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index fa66979..21f5424 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -2830,7 +2830,8 @@ void HMedistat_Think( gentity_t *self )
if( player->client && player->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
{
- if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] &&
+ if( ( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] ||
+ player->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX ) &&
PM_Live( player->client->ps.pm_type ) )
{
self->enemy = player;
@@ -2860,6 +2861,12 @@ void HMedistat_Think( gentity_t *self )
}
else if( self->enemy && self->enemy->client ) //heal!
{
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] < STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] += STAMINA_MEDISTAT_RESTORE;
+
+ if( self->enemy->client->ps.stats[ STAT_STAMINA ] > STAMINA_MAX )
+ self->enemy->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+
self->enemy->health++;
//if they're completely healed, give them a medkit
diff --git a/src/game/g_client.c b/src/game/g_client.c
index bfb79b9..896a7fc 100644
--- a/src/game/g_client.c
+++ b/src/game/g_client.c
@@ -1505,6 +1505,8 @@ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles
for( i = 0; i < MAX_CLIENTS; i++ )
ent->credits[ i ] = 0;
+ client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+
G_SetOrigin( ent, spawn_origin );
VectorCopy( spawn_origin, client->ps.origin );
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 74dea71..f3cada7 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -450,7 +450,7 @@ void Cmd_Give_f( gentity_t *ent )
if( trap_Argc( ) < 2 )
{
ADMP( "usage: give [what]\n" );
- ADMP( "usage: valid choices are: all, health, funds [amount], "
+ ADMP( "usage: valid choices are: all, health, funds [amount], stamina, "
"poison, gas, ammo\n" );
return;
}
@@ -487,6 +487,9 @@ void Cmd_Give_f( gentity_t *ent )
G_AddCreditToClient( ent->client, (short)credits, qtrue );
}
+ if( give_all || Q_stricmp( name, "stamina" ) == 0 )
+ ent->client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX;
+
if( Q_stricmp( name, "poison" ) == 0 )
{
if( ent->client->pers.teamSelection == TEAM_HUMANS )
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index 3db55f9..229e4ea 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -324,7 +324,21 @@ TREMULOUS EDGE MOD SRC FILE
* HUMAN
*/
+#define HUMAN_SPRINT_MODIFIER 1.28f
+#define HUMAN_JOG_MODIFIER 1.1f
+#define HUMAN_BACK_MODIFIER 0.8f
+#define HUMAN_SIDE_MODIFIER 0.9f
#define HUMAN_LAND_FRICTION 3.0f
+#define STAMINA_STOP_RESTORE 20
+#define STAMINA_WALK_RESTORE 15
+#define STAMINA_MEDISTAT_RESTORE 30
+#define STAMINA_SPRINT_TAKE 8
+#define STAMINA_JUMP_TAKE 250
+#define STAMINA_DODGE_TAKE 250
+#define STAMINA_MAX 1200
+#define STAMINA_BREATHING_LEVEL 0
+#define STAMINA_SLOW_LEVEL -500
+#define STAMINA_BLACKOUT_LEVEL -800
#define HUMAN_SPAWN_REPEAT_TIME 11000
#define HUMAN_REGEN_DAMAGE_TIME 2000 //msec since damage before dcc repairs
#define HUMAN_MAX_CREDITS 2000