summaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/game')
-rw-r--r--src/game/bg_misc.c15
-rw-r--r--src/game/bg_pmove.c192
-rw-r--r--src/game/bg_public.h4
-rw-r--r--src/game/g_active.c93
-rw-r--r--src/game/g_buildable.c2
-rw-r--r--src/game/g_cmds.c31
-rw-r--r--src/game/g_local.h1
-rw-r--r--src/game/g_missile.c13
-rw-r--r--src/game/g_weapon.c22
-rw-r--r--src/game/tremulous.h32
10 files changed, 206 insertions, 199 deletions
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index 5198fb28..02db5993 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -5430,6 +5430,21 @@ int BG_GetValueOfPlayer( playerState_t *ps )
}
/*
+=================
+BG_PlayerCanChangeWeapon
+=================
+*/
+qboolean BG_PlayerCanChangeWeapon( playerState_t *ps )
+{
+ // Do not allow Lucifer Cannon "canceling" via weapon switch
+ if( ps->weapon == WP_LUCIFER_CANNON &&
+ ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )
+ return qfalse;
+
+ return ps->weaponTime <= 0 || ps->weaponstate != WEAPON_FIRING;
+}
+
+/*
===============
atof_neg
diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c
index 51e1415c..d2c8acc5 100644
--- a/src/game/bg_pmove.c
+++ b/src/game/bg_pmove.c
@@ -404,8 +404,9 @@ static float PM_CmdScale( usercmd_t *cmd )
}
if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE )
- modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] /
- (float)LEVEL4_TRAMPLE_CHARGE_MAX ) * ( LEVEL4_TRAMPLE_SPEED - 1.0f ) );
+ modifier *= 1.0f + ( pm->ps->stats[ STAT_MISC ] *
+ ( LEVEL4_TRAMPLE_SPEED - 1.0f ) /
+ LEVEL4_TRAMPLE_CHARGE_MAX );
//slow player if charging up for a pounce
if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) &&
@@ -847,7 +848,7 @@ static qboolean PM_CheckDodge( void )
}
// Reasons to stop a sprint
- if( pm->cmd.forwardmove <= 64 ||
+ if( pm->cmd.forwardmove <= 0 ||
pm->cmd.upmove < 0 ||
pm->ps->pm_type != PM_NORMAL )
pm->ps->stats[ STAT_STATE ] &= ~SS_SPEEDBOOST;
@@ -2791,6 +2792,18 @@ static void PM_Weapon( void )
qboolean attack2 = qfalse;
qboolean attack3 = qfalse;
+ // Ignore weapons in some cases
+ if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ||
+ ( pm->ps->stats[ STAT_STATE ] & ( SS_INFESTING | SS_HOVELING ) ) )
+ return;
+
+ // Check for dead player
+ if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
+ {
+ pm->ps->weapon = WP_NONE;
+ return;
+ }
+
// Charging for a pounce or canceling a pounce
if( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
{
@@ -2809,43 +2822,96 @@ static void PM_Weapon( void )
pm->ps->stats[ STAT_MISC ] = 0;
}
- // Set overcharging flag so other players can hear warning
+ // Trample charge mechanics
+ if( pm->ps->weapon == WP_ALEVEL4 )
+ {
+ // Charging up
+ if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ // Charge button held
+ if( pm->ps->stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_MAX &&
+ ( pm->cmd.buttons & BUTTON_ATTACK2 ) )
+ {
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ if( pm->cmd.forwardmove > 0 )
+ pm->ps->stats[ STAT_MISC ] += pml.msec * LEVEL4_TRAMPLE_CHARGE_MAX /
+ LEVEL4_TRAMPLE_CHARGE_TIME_MAX;
+ else
+ pm->ps->stats[ STAT_MISC ] = 0;
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX )
+ {
+ pm->ps->stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX;
+ pm->ps->stats[ STAT_STATE ] |= SS_CHARGING;
+ PM_AddEvent( EV_LEV4_TRAMPLE_START );
+ }
+ }
+
+ // Charge button released
+ else if( !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) )
+ {
+ if( pm->ps->stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN )
+ {
+ pm->ps->stats[ STAT_STATE ] |= SS_CHARGING;
+ PM_AddEvent( EV_LEV4_TRAMPLE_START );
+ }
+ else
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+ }
+ }
+
+ // Discharging
+ else
+ {
+ pm->ps->stats[ STAT_MISC ] -= pml.msec;
+
+ // If the charger has stopped moving take a chunk of charge away
+ if( VectorLength( pm->ps->velocity ) < 64.0f || pm->cmd.rightmove )
+ pm->ps->stats[ STAT_MISC ] -= LEVEL4_TRAMPLE_STOP_PENALTY * pml.msec;
+ }
+
+ // Charge is over
+ if( pm->ps->stats[ STAT_MISC ] <= 0 || pm->cmd.forwardmove <= 0 )
+ {
+ pm->ps->stats[ STAT_MISC ] = 0;
+ pm->ps->stats[ STAT_STATE ] &= ~SS_CHARGING;
+ }
+ }
+
+ // Charging up a Lucifer Cannon
pm->ps->eFlags &= ~EF_WARN_CHARGE;
- if( pm->ps->weapon == WP_LUCIFER_CANNON &&
- pm->ps->stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE * 2 / 3 )
- pm->ps->eFlags |= EF_WARN_CHARGE;
+ if( pm->ps->weapon == WP_LUCIFER_CANNON )
+ {
+ // Charging up
+ if( !pm->ps->weaponTime && pm->ps->weaponstate != WEAPON_NEEDS_RESET &&
+ ( pm->cmd.buttons & BUTTON_ATTACK ) )
+ {
+ pm->ps->stats[ STAT_MISC ] += pml.msec;
+ if( pm->ps->stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_MAX )
+ pm->ps->stats[ STAT_MISC ] = LCANNON_CHARGE_TIME_MAX;
+ if( pm->ps->stats[ STAT_MISC ] > pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO )
+ pm->ps->stats[ STAT_MISC ] = pm->ps->ammo * LCANNON_CHARGE_TIME_MAX /
+ LCANNON_CHARGE_AMMO;
+ }
+
+ // Set overcharging flag so other players can hear the warning beep
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_WARN )
+ pm->ps->eFlags |= EF_WARN_CHARGE;
+ }
// don't allow attack until all buttons are up
if( pm->ps->pm_flags & PMF_RESPAWNED )
return;
- // ignore if spectator
- if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
- return;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING )
- return;
-
- if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING )
- return;
-
+ // no slash during charge
if( pm->ps->stats[ STAT_STATE ] & SS_CHARGING )
return;
- // check for dead player
- if( pm->ps->stats[ STAT_HEALTH ] <= 0 )
- {
- pm->ps->weapon = WP_NONE;
- return;
- }
-
// no bite during pounce
if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG )
- && ( pm->cmd.buttons & BUTTON_ATTACK )
- && ( pm->ps->pm_flags & PMF_CHARGE ) )
- {
+ && ( pm->cmd.buttons & BUTTON_ATTACK )
+ && ( pm->ps->pm_flags & PMF_CHARGE ) )
return;
- }
// make weapon function
if( pm->ps->weaponTime > 0 )
@@ -2853,15 +2919,10 @@ static void PM_Weapon( void )
if( pm->ps->weaponTime < 0 )
pm->ps->weaponTime = 0;
- if( pm->ps->stats[ STAT_MISC2 ] > 0 )
- pm->ps->stats[ STAT_MISC2 ] -= pml.msec;
- if( pm->ps->stats[ STAT_MISC2 ] < 0 )
- pm->ps->stats[ STAT_MISC2 ] = 0;
-
// check for weapon change
// can't change if weapon is firing, but can change
// again if lowering or raising
- if( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING )
+ if( BG_PlayerCanChangeWeapon( pm->ps ) )
{
// must press use to switch weapons
if( pm->cmd.buttons & BUTTON_USE_HOLDABLE )
@@ -2902,10 +2963,6 @@ static void PM_Weapon( void )
if( pm->ps->weaponTime > 0 )
return;
- // luci uses STAT_MISC2 as an alternate weaponTime
- if( pm->ps->weapon == WP_LUCIFER_CANNON && pm->ps->stats[ STAT_MISC2 ] > 0 )
- return;
-
// change weapon if time
if( pm->ps->weaponstate == WEAPON_DROPPING )
{
@@ -2913,10 +2970,10 @@ static void PM_Weapon( void )
return;
}
+ // Set proper animation
if( pm->ps->weaponstate == WEAPON_RAISING )
{
pm->ps->weaponstate = WEAPON_READY;
-
if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) )
{
if( pm->ps->weapon == WP_BLASTER )
@@ -2928,15 +2985,22 @@ static void PM_Weapon( void )
return;
}
- // start the animation even if out of ammo
-
BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips );
// check for out of ammo
if( !pm->ps->ammo && !pm->ps->clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
{
- PM_AddEvent( EV_NOAMMO );
- pm->ps->weaponTime += 200;
+ if( ( pm->cmd.buttons & BUTTON_ATTACK ) ||
+ ( BG_WeaponHasAltMode( pm->ps->weapon ) &&
+ ( pm->cmd.buttons & BUTTON_ATTACK2 ) ) ||
+ ( BG_WeaponHasThirdMode( pm->ps->weapon ) &&
+ ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) ) )
+ {
+ PM_AddEvent( EV_NOAMMO );
+ pm->ps->weaponTime += 500;
+ }
+ else
+ pm->ps->weaponTime += 50;
if( pm->ps->weaponstate == WEAPON_FIRING )
pm->ps->weaponstate = WEAPON_READY;
@@ -3002,7 +3066,6 @@ static void PM_Weapon( void )
case WP_LUCIFER_CANNON:
attack1 = pm->cmd.buttons & BUTTON_ATTACK;
attack2 = pm->cmd.buttons & BUTTON_ATTACK2;
- attack3 = qfalse;
// Prevent firing of the Lucifer Cannon after an overcharge
if( pm->ps->weaponstate == WEAPON_NEEDS_RESET )
@@ -3012,28 +3075,26 @@ static void PM_Weapon( void )
pm->ps->weaponstate = WEAPON_READY;
}
+ // Can't fire secondary while primary is charging
if( attack1 || pm->ps->stats[ STAT_MISC ] > 0 )
attack2 = qfalse;
- if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 )
+
+ if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 )
{
- attack2 = qfalse;
+ pm->ps->weaponTime = 0;
- if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE )
+ // Charging
+ if( pm->ps->stats[ STAT_MISC ] < LCANNON_CHARGE_TIME_MAX )
{
- // Charging
- pm->ps->weaponTime = 0;
pm->ps->weaponstate = WEAPON_READY;
return;
}
- else
- {
- // Overcharge
- pm->ps->weaponTime = 0;
- pm->ps->weaponstate = WEAPON_NEEDS_RESET;
- }
+
+ // Overcharge
+ pm->ps->weaponstate = WEAPON_NEEDS_RESET;
}
- if( pm->ps->stats[ STAT_MISC ] > LCANNON_MIN_CHARGE )
+ if( pm->ps->stats[ STAT_MISC ] > LCANNON_CHARGE_TIME_MIN )
{
// Fire primary attack
attack1 = qtrue;
@@ -3091,7 +3152,6 @@ static void PM_Weapon( void )
//hacky special case for slowblob
if( pm->ps->weapon == WP_ALEVEL3_UPG && !pm->ps->ammo )
{
- PM_AddEvent( EV_NOAMMO );
pm->ps->weaponTime += 200;
return;
}
@@ -3180,8 +3240,7 @@ static void PM_Weapon( void )
if( pm->ps->weapon == WP_ALEVEL4 )
{
//hack to get random attack animations
- //FIXME: does pm->ps->weaponTime cycle enough?
- int num = abs( pm->ps->weaponTime ) % 3;
+ int num = abs( pm->ps->commandTime ) % 3;
if( num == 0 )
PM_ForceLegsAnim( NSPA_ATTACK1 );
@@ -3209,17 +3268,16 @@ static void PM_Weapon( void )
// take an ammo away if not infinite
if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) )
{
- //special case for lcannon
+ // Special case for lcannon
if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 && !attack2 )
- {
- pm->ps->ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) );
-
- //stay on the safe side
- if( pm->ps->ammo < 0 )
- pm->ps->ammo = 0;
- }
+ pm->ps->ammo -= ( pm->ps->stats[ STAT_MISC ] * LCANNON_CHARGE_AMMO +
+ LCANNON_CHARGE_TIME_MAX - 1 ) / LCANNON_CHARGE_TIME_MAX;
else
pm->ps->ammo--;
+
+ // Stay on the safe side
+ if( pm->ps->ammo < 0 )
+ pm->ps->ammo = 0;
}
else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 )
{
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index e3ffc434..54101188 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -217,7 +217,7 @@ typedef enum
STAT_STAMINA, // stamina (human only)
STAT_STATE, // client states e.g. wall climbing
STAT_MISC, // for uh...misc stuff (pounce, trample, lcannon)
- STAT_MISC2, // more uh...misc stuff (booster, lcannon repeat)
+ STAT_UNUSED, // *** UNUSED ***
STAT_BUILDABLE, // which ghost model to display for building
STAT_FALLDIST, // the distance the player fell
STAT_VIEWLOCK // direction to lock the view in
@@ -1130,6 +1130,7 @@ void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps,
const vec3_t, const vec3_t, int, int ),
vec3_t outOrigin, vec3_t outAngles, trace_t *tr );
int BG_GetValueOfPlayer( playerState_t *ps );
+qboolean BG_PlayerCanChangeWeapon( playerState_t *ps );
int BG_FindValueOfBuildable( int bclass );
int BG_FindBuildNumForName( char *name );
@@ -1316,7 +1317,6 @@ qboolean BG_WeaponIsAllowed( weapon_t weapon );
qboolean BG_UpgradeIsAllowed( upgrade_t upgrade );
qboolean BG_ClassIsAllowed( pClass_t class );
qboolean BG_BuildableIsAllowed( buildable_t buildable );
-qboolean BG_UpgradeClassAvailable( playerState_t *ps );
typedef struct
{
diff --git a/src/game/g_active.c b/src/game/g_active.c
index f232781b..74cb28e2 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -613,84 +613,6 @@ void ClientTimerActions( gentity_t *ent, int msec )
else if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA )
client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA;
- //client is charging up for a... charge
- if( client->ps.weapon == WP_ALEVEL4 )
- {
- if( client->ps.stats[ STAT_MISC ] < LEVEL4_TRAMPLE_CHARGE_TRIGGER &&
- ( ucmd->buttons & BUTTON_ATTACK2 ) && !client->charging )
- {
- client->charging = qfalse; //should already be off, just making sure
- client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING;
-
- if( ucmd->forwardmove > 0 )
- {
- //trigger charge sound...is quite annoying
- //if( client->ps.stats[ STAT_MISC ] <= 0 )
- // G_AddEvent( ent, EV_LEV4_TRAMPLE_PREPARE, 0 );
-
- client->ps.stats[ STAT_MISC ] += 100 * LEVEL4_TRAMPLE_CHARGE_RATE;
-
- }
- else
- client->ps.stats[ STAT_MISC ] = 0;
-
- }
-
- if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging ||
- client->ps.stats[ STAT_MISC ] >= LEVEL4_TRAMPLE_CHARGE_TRIGGER )
- {
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MIN )
- {
- client->ps.stats[ STAT_MISC ] -= 100 * LEVEL4_TRAMPLE_DISCHARGE_RATE;
-
- if( client->charging == qfalse )
- G_AddEvent( ent, EV_LEV4_TRAMPLE_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 || strafing )
- 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;
- if( client->ps.stats[ STAT_MISC ] > LEVEL4_TRAMPLE_CHARGE_MAX )
- client->ps.stats[ STAT_MISC ] = LEVEL4_TRAMPLE_CHARGE_MAX;
- }
- 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;
- }
- }
- }
-
- //client is charging up an lcannon
- if( client->ps.weapon == WP_LUCIFER_CANNON &&
- ( ucmd->buttons & BUTTON_ATTACK ) &&
- client->ps.stats[ STAT_MISC2 ] <= 0 &&
- client->ps.weaponstate != WEAPON_NEEDS_RESET )
- {
- if( client->ps.stats[ STAT_MISC ] <= 0 )
- client->lcannonStartTime = level.time;
-
- if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE )
- client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE )
- client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE;
-
- if( client->ps.stats[ STAT_MISC ] > ( client->ps.ammo * LCANNON_TOTAL_CHARGE ) / 10 )
- client->ps.stats[ STAT_MISC ] = client->ps.ammo * LCANNON_TOTAL_CHARGE / 10;
- }
-
if( client->ps.weapon == WP_ABUILD || client->ps.weapon == WP_ABUILD2 ||
BG_InventoryContainsWeapon( WP_HBUILD, client->ps.stats ) )
{
@@ -1477,20 +1399,20 @@ void ClientThink_real( gentity_t *ent )
else
client->ps.pm_type = PM_NORMAL;
- if( client->ps.stats[ STAT_STATE ] & SS_GRABBED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_GRABBED ) &&
client->grabExpiryTime < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED;
- if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ) &&
client->lastLockTime + LOCKBLOB_LOCKTIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_BLOBLOCKED;
- if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED &&
+ if( ( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED ) &&
client->lastSlowTime + ABUILDER_BLOB_TIME < level.time )
client->ps.stats[ STAT_STATE ] &= ~SS_SLOWLOCKED;
- if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED &&
- client->ps.stats[ STAT_MISC2 ] <= 0 )
+ if( ( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) &&
+ level.time - client->boostedTime >= BOOST_TIME )
client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED;
if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED )
@@ -1891,11 +1813,10 @@ void SpectatorClientEndFrame( gentity_t *ent )
( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) );
ent->client->ps = cl->ps;
ent->client->ps.eFlags = flags;
- ent->client->ps.pm_flags |= PMF_FOLLOW;
}
- else
- ent->client->ps.pm_flags &= ~PMF_FOLLOW;
+
ent->client->ps.clientNum = clientNum;
+ ent->client->ps.pm_flags |= PMF_FOLLOW;
ent->client->ps.pm_flags &= ~PMF_QUEUED;
}
}
diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c
index 1a532ca1..1ef65f43 100644
--- a/src/game/g_buildable.c
+++ b/src/game/g_buildable.c
@@ -1467,7 +1467,7 @@ void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace )
return;
client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- client->ps.stats[ STAT_MISC2 ] = BOOST_TIME;
+ client->boostedTime = level.time;
}
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index 88d11646..56f8e8eb 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -367,7 +367,7 @@ void Cmd_Give_f( gentity_t *ent )
if( Q_stricmp( name, "poison" ) == 0 )
{
ent->client->ps.stats[ STAT_STATE ] |= SS_BOOSTED;
- ent->client->ps.stats[ STAT_MISC2 ] = BOOST_TIME;
+ ent->client->boostedTime = level.time;
}
if( give_all || Q_stricmp( name, "ammo" ) == 0 )
@@ -1830,13 +1830,14 @@ void Cmd_ActivateItem_f( gentity_t *ent )
{
char s[ MAX_TOKEN_CHARS ];
int upgrade, weapon;
-
+
trap_Argv( 1, s, sizeof( s ) );
// "weapon" aliased to whatever weapon you have
if( !Q_stricmp( "weapon", s ) )
{
- if( ent->client->ps.weapon == WP_BLASTER )
+ if( ent->client->ps.weapon == WP_BLASTER &&
+ BG_PlayerCanChangeWeapon( &ent->client->ps ) )
G_ForceWeaponChange( ent, WP_NONE );
return;
}
@@ -1849,7 +1850,8 @@ void Cmd_ActivateItem_f( gentity_t *ent )
else if( weapon != WP_NONE &&
BG_InventoryContainsWeapon( weapon, ent->client->ps.stats ) )
{
- if( ent->client->ps.weapon != weapon )
+ if( ent->client->ps.weapon != weapon &&
+ BG_PlayerCanChangeWeapon( &ent->client->ps ) )
G_ForceWeaponChange( ent, weapon );
}
else
@@ -1895,9 +1897,11 @@ void Cmd_ToggleItem_f( gentity_t *ent )
if( weapon != WP_NONE )
{
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
+
//special case to allow switching between
//the blaster and the primary weapon
-
if( ent->client->ps.weapon != WP_BLASTER )
weapon = WP_BLASTER;
else
@@ -2037,6 +2041,9 @@ void Cmd_Buy_f( gentity_t *ent )
trap_SendServerCommand( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
}
+
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
//add to inventory
BG_AddWeaponToInventory( weapon, ent->client->ps.stats );
@@ -2164,6 +2171,9 @@ void Cmd_Sell_f( gentity_t *ent )
if( weapon != WP_NONE )
{
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
+
//are we /allowed/ to sell this?
if( !BG_FindPurchasableForWeapon( weapon ) )
{
@@ -2229,6 +2239,9 @@ void Cmd_Sell_f( gentity_t *ent )
}
else if( !Q_stricmp( s, "weapons" ) )
{
+ if( !BG_PlayerCanChangeWeapon( &ent->client->ps ) )
+ return;
+
for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ )
{
//guard against selling the HBUILD weapons exploit
@@ -2502,8 +2515,10 @@ void G_FollowLockView( gentity_t *ent )
vec3_t spawn_origin, spawn_angles;
int clientNum;
+ clientNum = ent->client->sess.spectatorClient;
ent->client->sess.sessionTeam = TEAM_SPECTATOR;
ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+ ent->client->ps.clientNum = clientNum;
ent->client->ps.persistant[ PERS_TEAM ] = TEAM_SPECTATOR;
ent->client->ps.pm_flags &= ~PMF_FOLLOW;
ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection;
@@ -2512,7 +2527,6 @@ void G_FollowLockView( gentity_t *ent )
ent->client->ps.stats[ STAT_VIEWLOCK ] = 0;
ent->client->ps.eFlags &= ~EF_WALLCLIMB;
ent->client->ps.viewangles[ PITCH ] = 0.0f;
- clientNum = ent->client->ps.clientNum = ent->client->sess.spectatorClient;
// Put the view at the team spectator lock position
if( level.clients[ clientNum ].pers.teamSelection == PTE_ALIENS )
@@ -2595,6 +2609,11 @@ qboolean G_FollowNewClient( gentity_t *ent, int dir )
// this is good, we can use it
ent->client->sess.spectatorClient = clientnum;
ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
+
+ // if this client is in the spawn queue, we need to do something special
+ if( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR )
+ G_FollowLockView( ent );
+
return qtrue;
} while( clientnum != original );
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 0305c3c9..0c2e6d7d 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -423,6 +423,7 @@ struct gclient_s
int inactivityTime; // kick players when time > this
qboolean inactivityWarning;// qtrue if the five seoond warning has been given
int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
+ int boostedTime; // last time we touched a booster
int airOutTime;
diff --git a/src/game/g_missile.c b/src/game/g_missile.c
index 2991ec48..4d5a751a 100644
--- a/src/game/g_missile.c
+++ b/src/game/g_missile.c
@@ -438,15 +438,13 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,
int damage, int radius, int speed )
{
gentity_t *bolt;
- int localDamage = (int)( ceil( ( (float)damage /
- (float)LCANNON_TOTAL_CHARGE ) * (float)LCANNON_DAMAGE ) );
VectorNormalize( dir );
bolt = G_Spawn( );
bolt->classname = "lcannon";
- if( damage == LCANNON_TOTAL_CHARGE )
+ if( damage == LCANNON_DAMAGE )
bolt->nextthink = level.time;
else
bolt->nextthink = level.time + 10000;
@@ -458,8 +456,8 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,
bolt->s.generic1 = self->s.generic1; //weaponMode
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
- bolt->damage = localDamage;
- bolt->splashDamage = localDamage / 2;
+ bolt->damage = damage;
+ bolt->splashDamage = damage / 2;
bolt->splashRadius = radius;
bolt->methodOfDeath = MOD_LCANNON;
bolt->splashMethodOfDeath = MOD_LCANNON_SPLASH;
@@ -467,7 +465,10 @@ gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,
bolt->target_ent = NULL;
// Pass the missile charge through
- bolt->s.torsoAnim = damage;
+ bolt->s.torsoAnim = ( damage - LCANNON_SECONDARY_DAMAGE ) *
+ 255 / LCANNON_DAMAGE;
+ if( bolt->s.torsoAnim < 0 )
+ bolt->s.torsoAnim = 0;
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_weapon.c b/src/game/g_weapon.c
index fc915d86..f5a118fa 100644
--- a/src/game/g_weapon.c
+++ b/src/game/g_weapon.c
@@ -772,18 +772,13 @@ void LCChargeFire( gentity_t *ent, qboolean secondary )
gentity_t *m;
if( secondary && ent->client->ps.stats[ STAT_MISC ] <= 0 )
- {
m = fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE,
- LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED );
- ent->client->ps.stats[ STAT_MISC2 ] = LCANNON_REPEAT;
- }
+ LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED );
else
- {
m = fire_luciferCannon( ent, muzzle, forward,
- ent->client->ps.stats[ STAT_MISC ], LCANNON_RADIUS, LCANNON_SPEED );
- ent->client->ps.stats[ STAT_MISC2 ] = LCANNON_CHARGEREPEAT -
- ( level.time - ent->client->lcannonStartTime );
- }
+ ent->client->ps.stats[ STAT_MISC ] *
+ LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX,
+ LCANNON_RADIUS, LCANNON_SPEED );
ent->client->ps.stats[ STAT_MISC ] = 0;
}
@@ -1360,7 +1355,8 @@ void G_ChargeAttack( gentity_t *ent, gentity_t *victim )
int damage;
vec3_t forward, normal;
- if( ent->client->ps.stats[ STAT_MISC ] <= 0 || !ent->client->charging )
+ if( ent->client->ps.stats[ STAT_MISC ] <= 0 ||
+ !( ent->client->ps.stats[ STAT_STATE ] & SS_CHARGING ) )
return;
VectorSubtract( victim->s.origin, ent->s.origin, forward );
@@ -1372,11 +1368,11 @@ void G_ChargeAttack( gentity_t *ent, gentity_t *victim )
WideBloodSpurt( ent, victim, NULL );
- damage = (int)( ( (float)ent->client->ps.stats[ STAT_MISC ] /
- (float)LEVEL4_TRAMPLE_CHARGE_MAX ) * LEVEL4_TRAMPLE_DMG );
+ damage = LEVEL4_TRAMPLE_DMG * ent->client->ps.stats[ STAT_MISC ] /
+ LEVEL4_TRAMPLE_CHARGE_MAX;
G_Damage( victim, ent, ent, forward, victim->s.origin, damage,
- 0, MOD_LEVEL4_TRAMPLE );
+ 0, MOD_LEVEL4_TRAMPLE );
if( !victim->client )
ent->client->ps.stats[ STAT_MISC ] = 0;
diff --git a/src/game/tremulous.h b/src/game/tremulous.h
index 3bbac18f..585abe5d 100644
--- a/src/game/tremulous.h
+++ b/src/game/tremulous.h
@@ -115,24 +115,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define LEVEL4_CLAW_K_SCALE 1.0f
#define LEVEL4_REGEN_RANGE 200.0f
+#define LEVEL4_TRAMPLE_DMG ADM(110)
#define LEVEL4_TRAMPLE_SPEED 2.0f
-#define LEVEL4_TRAMPLE_TRIGGER_TIME 3000
-#define LEVEL4_TRAMPLE_CHARGE_MIN_TIME 375
-#define LEVEL4_TRAMPLE_CHARGE_MAX_TIME 1000
+#define LEVEL4_TRAMPLE_CHARGE_TIME_MIN 375
+#define LEVEL4_TRAMPLE_CHARGE_TIME_MAX 1000
#define LEVEL4_TRAMPLE_DURATION 3000
-#define LEVEL4_TRAMPLE_DMG ADM(110)
+#define LEVEL4_TRAMPLE_STOP_PENALTY 1 // msec of charge lost when stopped
+
+#define LEVEL4_TRAMPLE_CHARGE_MIN ( LEVEL4_TRAMPLE_CHARGE_TIME_MIN * \
+ LEVEL4_TRAMPLE_DURATION / \
+ LEVEL4_TRAMPLE_CHARGE_TIME_MAX )
+#define LEVEL4_TRAMPLE_CHARGE_MAX LEVEL4_TRAMPLE_DURATION
-#define LEVEL4_TRAMPLE_CHARGE_RATE 2.0f
-#define LEVEL4_TRAMPLE_CHARGE_TRIGGER ( LEVEL4_TRAMPLE_TRIGGER_TIME * \
- LEVEL4_TRAMPLE_CHARGE_RATE )
-#define LEVEL4_TRAMPLE_CHARGE_MIN ( LEVEL4_TRAMPLE_CHARGE_MIN_TIME * \
- LEVEL4_TRAMPLE_CHARGE_RATE )
-#define LEVEL4_TRAMPLE_CHARGE_MAX ( LEVEL4_TRAMPLE_CHARGE_MAX_TIME * \
- LEVEL4_TRAMPLE_CHARGE_RATE )
-#define LEVEL4_TRAMPLE_DISCHARGE_RATE ( (float)LEVEL4_TRAMPLE_CHARGE_MAX / \
- (float)LEVEL4_TRAMPLE_DURATION )
-
-#define LEVEL4_CRUSH_DAMAGE_PER_V 0.5f
+#define LEVEL4_CRUSH_DAMAGE_PER_V 0.5f // damage per falling velocity
#define LEVEL4_CRUSH_DAMAGE 120 // to players only
#define LEVEL4_CRUSH_REPEAT 500 // player damage repeat
@@ -471,9 +466,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define LCANNON_SECONDARY_SPEED 1400
#define LCANNON_SECONDARY_RELOAD 2000
#define LCANNON_SPEED 700
-#define LCANNON_CHARGE_TIME 3000
-#define LCANNON_TOTAL_CHARGE 255
-#define LCANNON_MIN_CHARGE 1
+#define LCANNON_CHARGE_TIME_MAX 3000
+#define LCANNON_CHARGE_TIME_MIN 100
+#define LCANNON_CHARGE_TIME_WARN 2000
+#define LCANNON_CHARGE_AMMO 10 // ammo cost of a full charge shot
#define HBUILD_PRICE 0
#define HBUILD_REPEAT 1000