From 0cf04fe37fef2e827a95bb19926a3cbf8e98c581 Mon Sep 17 00:00:00 2001 From: Michael Levin Date: Sat, 3 Oct 2009 11:26:51 +0000 Subject: * Added charge meter to the UI, can be disabled via GUI * Trample and Lucifer Cannon charging reworked and moved to PMove * Can no longer "cancel" a charging Lucifer Cannon * STAT_MISC2 is now unused, booster and charge information can be inferred elsewhere (STAT_UNUSED) * Trying to fire an empty weapon makes a clicking noise (also a bugfix, apparently the server would spam EV_NOAMMO which did nothing but is now used for the clicking noise -- audible to all players) * Created an alternate, muffled Lucifer Cannon warning noise for other people's Lucifer Cannons * Fixed bug which prevented players from switching to a different player while spectating someone in the spawn queue * Spectators are now properly moved to the lock view position when spectating a player in the spawn queue --- src/cgame/cg_draw.c | 141 ++++++++++++++++++++++++++++++++---- src/cgame/cg_event.c | 4 +- src/cgame/cg_local.h | 8 +++ src/cgame/cg_main.c | 6 +- src/cgame/cg_view.c | 2 +- src/cgame/cg_weapons.c | 33 ++++----- src/game/bg_misc.c | 15 ++++ src/game/bg_pmove.c | 192 ++++++++++++++++++++++++++++++++----------------- src/game/bg_public.h | 4 +- src/game/g_active.c | 93 ++---------------------- src/game/g_buildable.c | 2 +- src/game/g_cmds.c | 31 ++++++-- src/game/g_local.h | 1 + src/game/g_missile.c | 13 ++-- src/game/g_weapon.c | 22 +++--- src/game/tremulous.h | 32 ++++----- 16 files changed, 364 insertions(+), 235 deletions(-) (limited to 'src') diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index 08433c44..5002fc9a 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -588,21 +588,15 @@ CG_DrawPlayerBoosterBolt */ static void CG_DrawPlayerBoosterBolt( rectDef_t *rect, vec4_t color, qhandle_t shader ) { - vec4_t localColor; - playerState_t *ps = &cg.snap->ps; + vec4_t localColor; Vector4Copy( color, localColor ); - if( ps->stats[ STAT_STATE ] & SS_BOOSTED ) - { - if( ps->stats[ STAT_MISC2 ] < 3000 ) - { - qboolean flash = ( ps->stats[ STAT_MISC2 ] / 500 ) % 2; - - if( flash ) - localColor[ 3 ] = 1.0f; - } - } + // Flash bolts when the boost is almost out + if( ( cg.snap->ps.stats[ STAT_STATE ] & SS_BOOSTED ) && + cg.boostedTime > 0 && cg.time - cg.boostedTime > BOOST_TIME - 5000 && + cg.time & 256 ) + localColor[ 3 ] = 1.0f; trap_R_SetColor( localColor ); CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); @@ -904,6 +898,123 @@ static void CG_DrawPlayerHealthCross3( rectDef_t *rect, vec4_t color, qhandle_t trap_R_SetColor( NULL ); } +static float CG_ChargeProgress( void ) +{ + float progress; + int min = 0, max = 0; + + if( cg.snap->ps.weapon == WP_ALEVEL3 ) + { + min = LEVEL3_POUNCE_TIME_MIN; + max = LEVEL3_POUNCE_TIME; + } + else if( cg.snap->ps.weapon == WP_ALEVEL3_UPG ) + { + min = LEVEL3_POUNCE_TIME_MIN; + max = LEVEL3_POUNCE_TIME_UPG; + } + else if( cg.snap->ps.weapon == WP_ALEVEL4 ) + { + min = LEVEL4_TRAMPLE_CHARGE_MIN; + max = LEVEL4_TRAMPLE_CHARGE_MAX; + } + else if( cg.snap->ps.weapon == WP_LUCIFER_CANNON ) + { + min = LCANNON_CHARGE_TIME_MIN; + max = LCANNON_CHARGE_TIME_MAX; + } + if( max - min < 0.0f ) + return 0.0f; + progress = ( (float)cg.predictedPlayerState.stats[ STAT_MISC ] - min ) / + ( max - min ); + if( progress > 1.0f ) + return 1.0f; + if( progress < 0.0f ) + return 0.0f; + return progress; +} + +#define CHARGE_BAR_FADE_RATE 0.002f + +static void CG_DrawPlayerChargeBarBG( rectDef_t *rect, vec4_t ref_color, + qhandle_t shader ) +{ + vec4_t color; + + if( !cg_drawChargeBar.integer || cg.chargeMeterAlpha <= 0.0f ) + return; + + color[ 0 ] = ref_color[ 0 ]; + color[ 1 ] = ref_color[ 1 ]; + color[ 2 ] = ref_color[ 2 ]; + color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha; + + // Draw meter background + trap_R_SetColor( color ); + CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); + trap_R_SetColor( NULL ); +} + +static void CG_DrawPlayerChargeBar( rectDef_t *rect, vec4_t ref_color, + qhandle_t shader ) +{ + vec4_t color; + float x, y, width, height, cap_width, progress; + + if( !cg_drawChargeBar.integer ) + return; + + // Get progress proportion and pump fade + progress = CG_ChargeProgress(); + if( progress <= 0.0f ) + { + cg.chargeMeterAlpha -= CHARGE_BAR_FADE_RATE * cg.frametime; + if( cg.chargeMeterAlpha <= 0.0f ) + { + cg.chargeMeterAlpha = 0.0f; + return; + } + } + else + { + cg.chargeMeterValue = progress; + cg.chargeMeterAlpha += CHARGE_BAR_FADE_RATE * cg.frametime; + if( cg.chargeMeterAlpha > 1.0f ) + cg.chargeMeterAlpha = 1.0f; + } + + color[ 0 ] = ref_color[ 0 ]; + color[ 1 ] = ref_color[ 1 ]; + color[ 2 ] = ref_color[ 2 ]; + color[ 3 ] = ref_color[ 3 ] * cg.chargeMeterAlpha; + + // Flash red for Lucifer Cannon warning + if( cg.snap->ps.weapon == WP_LUCIFER_CANNON && + cg.snap->ps.stats[ STAT_MISC ] >= LCANNON_CHARGE_TIME_WARN && + ( cg.time & 128 ) ) + { + color[ 0 ] = 1.0f; + color[ 1 ] = 0.0f; + color[ 2 ] = 0.0f; + } + + // Calculate bar coords + x = rect->x; + y = rect->y; + width = ( rect->w - 6 ) * cg.chargeMeterValue; + height = rect->h; + CG_AdjustFrom640( &x, &y, &width, &height ); + cap_width = 3 * cgs.screenXScale; + + // Draw the meter + trap_R_SetColor( color ); + trap_R_DrawStretchPic( x, y, cap_width, height, 0, 0, 1, 1, shader ); + trap_R_DrawStretchPic( x + width + cap_width, y, cap_width, height, + 1, 0, 0, 1, shader ); + trap_R_DrawStretchPic( x + cap_width, y, width, height, 1, 0, 1, 1, shader ); + trap_R_SetColor( NULL ); +} + static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color, float scale, int textalign, int textvalign, const char *s, float fraction ) @@ -2151,6 +2262,12 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x, case CG_PLAYER_HEALTH_CROSS3: CG_DrawPlayerHealthCross3( &rect, color, shader ); break; + case CG_PLAYER_CHARGE_BAR_BG: + CG_DrawPlayerChargeBarBG( &rect, color, shader ); + break; + case CG_PLAYER_CHARGE_BAR: + CG_DrawPlayerChargeBar( &rect, color, shader ); + break; case CG_PLAYER_CLIPS_RING: CG_DrawPlayerClipsRing( &rect, color, shader ); break; diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index 9b6afbe6..2d622088 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -737,8 +737,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) // case EV_NOAMMO: DEBUGNAME( "EV_NOAMMO" ); - { - } + trap_S_StartSound( NULL, es->number, CHAN_WEAPON, + cgs.media.weaponEmptyClick ); break; case EV_CHANGE_WEAPON: diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 360dac34..8dfd09a4 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1133,6 +1133,11 @@ typedef struct playerState_t savedPmoveStates[ NUM_SAVED_STATES ]; int stateHead, stateTail; int ping; + + float chargeMeterAlpha; + float chargeMeterValue; + + int nextWeaponClickTime; } cg_t; @@ -1179,6 +1184,7 @@ typedef struct // sounds sfxHandle_t tracerSound; + sfxHandle_t weaponEmptyClick; sfxHandle_t selectSound; sfxHandle_t footsteps[ FOOTSTEP_TOTAL ][ 4 ]; sfxHandle_t talkSound; @@ -1263,6 +1269,7 @@ typedef struct qhandle_t massDriverTS; sfxHandle_t lCannonWarningSound; + sfxHandle_t lCannonWarningSound2; qhandle_t buildWeaponTimerPie[ 8 ]; qhandle_t upgradeClassIconShader; @@ -1409,6 +1416,7 @@ extern vmCvar_t cg_drawSnapshot; extern vmCvar_t cg_draw3dIcons; extern vmCvar_t cg_drawIcons; extern vmCvar_t cg_drawAmmoWarning; +extern vmCvar_t cg_drawChargeBar; extern vmCvar_t cg_drawCrosshair; extern vmCvar_t cg_drawCrosshairNames; extern vmCvar_t cg_drawRewards; diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index ac0715fe..a2027b3e 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -125,6 +125,7 @@ vmCvar_t cg_drawSnapshot; vmCvar_t cg_draw3dIcons; vmCvar_t cg_drawIcons; vmCvar_t cg_drawAmmoWarning; +vmCvar_t cg_drawChargeBar; vmCvar_t cg_drawCrosshair; vmCvar_t cg_drawCrosshairNames; vmCvar_t cg_drawRewards; @@ -268,6 +269,7 @@ static cvarTable_t cvarTable[ ] = { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE }, { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE }, { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE }, + { &cg_drawChargeBar, "cg_drawChargeBar", "1", CVAR_ARCHIVE }, { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE }, { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, @@ -692,6 +694,7 @@ static void CG_RegisterSounds( void ) cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/tracer.wav", qfalse ); cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse ); cgs.media.turretSpinupSound = trap_S_RegisterSound( "sound/buildables/mgturret/spinup.wav", qfalse ); + cgs.media.weaponEmptyClick = trap_S_RegisterSound( "sound/weapons/click.wav", qfalse ); cgs.media.talkSound = trap_S_RegisterSound( "sound/misc/talk.wav", qfalse ); cgs.media.alienTalkSound = trap_S_RegisterSound( "sound/misc/alien_talk.wav", qfalse ); @@ -760,6 +763,7 @@ static void CG_RegisterSounds( void ) cgs.media.buildableRepairedSound = trap_S_RegisterSound( "sound/buildables/human/repaired.wav", qfalse ); cgs.media.lCannonWarningSound = trap_S_RegisterSound( "models/weapons/lcannon/warning.wav", qfalse ); + cgs.media.lCannonWarningSound2 = trap_S_RegisterSound( "models/weapons/lcannon/warning2.wav", qfalse ); } @@ -835,7 +839,7 @@ static void CG_RegisterGraphics( void ) cgs.media.buildWeaponTimerPie[ i ] = trap_R_RegisterShader( buildWeaponTimerPieShaders[ i ] ); cgs.media.upgradeClassIconShader = trap_R_RegisterShader( "icons/icona_upgrade.tga" ); - + cgs.media.balloonShader = trap_R_RegisterShader( "gfx/sprites/chatballoon" ); cgs.media.disconnectPS = CG_RegisterParticleSystem( "disconnectPS" ); diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index 2c718556..9772e1f5 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -471,7 +471,7 @@ static void CG_OffsetFirstPersonView( void ) if( ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / - (float)LEVEL4_TRAMPLE_CHARGE_MAX; + LEVEL4_TRAMPLE_CHARGE_MAX; if( fraction > 1.0f ) fraction = 1.0f; diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c index f4c8fbf8..d0968dd9 100644 --- a/src/cgame/cg_weapons.c +++ b/src/cgame/cg_weapons.c @@ -872,8 +872,9 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent // Lucifer cannon charge warning beep if( weaponNum == WP_LUCIFER_CANNON && ( cent->currentState.eFlags & EF_WARN_CHARGE ) ) - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.lCannonWarningSound ); + trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, + vec3_origin, ps ? cgs.media.lCannonWarningSound : + cgs.media.lCannonWarningSound2 ); if( !noGunModel ) { @@ -987,6 +988,9 @@ CG_AddViewWeapon Add the weapon, and flash for the player's view ============== */ + +#define WEAPON_CLICK_REPEAT 500 + void CG_AddViewWeapon( playerState_t *ps ) { refEntity_t hand; @@ -1072,27 +1076,16 @@ void CG_AddViewWeapon( playerState_t *ps ) VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[ 1 ], hand.origin ); VectorMA( hand.origin, ( cg_gun_z.value + fovOffset ), cg.refdef.viewaxis[ 2 ], hand.origin ); - if( weapon == WP_LUCIFER_CANNON ) + // Lucifer Cannon vibration effect + if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 ) { float fraction; - if( ps->stats[ STAT_MISC ] > 0 ) - { - // vibration effect - fraction = (float)ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE; - VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], - hand.origin ); - VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], - hand.origin ); - } - else if( ps->stats[ STAT_MISC2 ] > 0 ) - { - // reloading effect - fraction = (float)ps->stats[ STAT_MISC2 ] / 250.0f; - fraction = ( fraction > 1.0f ) ? 1.0f : fraction; - VectorMA( hand.origin, fraction * -3.0f, cg.refdef.viewaxis[ 2 ], - hand.origin ); - } + fraction = (float)ps->stats[ STAT_MISC ] / LCANNON_CHARGE_TIME_MAX; + VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], + hand.origin ); + VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], + hand.origin ); } AnglesToAxis( angles, hand.axis ); 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 @@ -5429,6 +5429,21 @@ int BG_GetValueOfPlayer( playerState_t *ps ) return worth; } +/* +================= +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 -- cgit