You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
12 KiB
430 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// |
|
//============================================================================= |
|
#include "cbase.h" |
|
#include "tf_weapon_lunchbox.h" |
|
#include "tf_fx_shared.h" |
|
|
|
// Client specific. |
|
#ifdef CLIENT_DLL |
|
#include "c_tf_player.h" |
|
// Server specific. |
|
#else |
|
#include "tf_player.h" |
|
#include "entity_healthkit.h" |
|
#include "econ_item_view.h" |
|
#include "econ_item_system.h" |
|
#include "tf_gamestats.h" |
|
#endif |
|
|
|
//============================================================================= |
|
// |
|
// Weapon Lunchbox tables. |
|
// |
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFLunchBox, DT_WeaponLunchBox ) |
|
|
|
BEGIN_NETWORK_TABLE( CTFLunchBox, DT_WeaponLunchBox ) |
|
END_NETWORK_TABLE() |
|
|
|
BEGIN_PREDICTION_DATA( CTFLunchBox ) |
|
END_PREDICTION_DATA() |
|
|
|
LINK_ENTITY_TO_CLASS( tf_weapon_lunchbox, CTFLunchBox ); |
|
PRECACHE_WEAPON_REGISTER( tf_weapon_lunchbox ); |
|
|
|
//============================================================================= |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFLunchBox_Drink, DT_TFLunchBox_Drink ) |
|
|
|
BEGIN_NETWORK_TABLE( CTFLunchBox_Drink, DT_TFLunchBox_Drink ) |
|
END_NETWORK_TABLE() |
|
|
|
BEGIN_PREDICTION_DATA( CTFLunchBox_Drink ) |
|
END_PREDICTION_DATA() |
|
|
|
LINK_ENTITY_TO_CLASS( tf_weapon_lunchbox_drink, CTFLunchBox_Drink ); |
|
PRECACHE_WEAPON_REGISTER( tf_weapon_lunchbox_drink ); |
|
|
|
// Server specific. |
|
#ifndef CLIENT_DLL |
|
BEGIN_DATADESC( CTFLunchBox ) |
|
END_DATADESC() |
|
#endif |
|
|
|
#define LUNCHBOX_DROP_MODEL "models/items/plate.mdl" |
|
#define LUNCHBOX_STEAK_DROP_MODEL "models/items/plate_steak.mdl" |
|
#define LUNCHBOX_ROBOT_DROP_MODEL "models/items/plate_robo_sandwich.mdl" |
|
#define LUNCHBOX_FESTIVE_DROP_MODEL "models/items/plate_sandwich_xmas.mdl" |
|
#define LUNCHBOX_CHOCOLATE_BAR "models/props_halloween/halloween_medkit_small.mdl" |
|
|
|
#define LUNCHBOX_DROPPED_MINS Vector( -17, -17, -10 ) |
|
#define LUNCHBOX_DROPPED_MAXS Vector( 17, 17, 10 ) |
|
|
|
static const char *s_pszLunchboxMaxHealThink = "LunchboxMaxHealThink"; |
|
|
|
//============================================================================= |
|
// |
|
// Weapon Lunchbox functions. |
|
// |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFLunchBox::CTFLunchBox() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::UpdateOnRemove( void ) |
|
{ |
|
#ifndef CLIENT_DLL |
|
// If we're removed, we remove any dropped powerups. This prevents an exploit |
|
// where they switch classes away & back to get another lunchbox to drop with. |
|
if ( m_hThrownPowerup ) |
|
{ |
|
UTIL_Remove( m_hThrownPowerup ); |
|
} |
|
#endif |
|
|
|
BaseClass::UpdateOnRemove(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::Precache( void ) |
|
{ |
|
if ( DropAllowed() ) |
|
{ |
|
PrecacheModel( "models/items/medkit_medium.mdl" ); |
|
PrecacheModel( "models/items/medkit_medium_bday.mdl" ); |
|
PrecacheModel( LUNCHBOX_DROP_MODEL ); |
|
PrecacheModel( LUNCHBOX_STEAK_DROP_MODEL ); |
|
PrecacheModel( LUNCHBOX_ROBOT_DROP_MODEL ); |
|
PrecacheModel( LUNCHBOX_FESTIVE_DROP_MODEL ); |
|
PrecacheModel( LUNCHBOX_CHOCOLATE_BAR ); |
|
} |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::WeaponReset( void ) |
|
{ |
|
BaseClass::WeaponReset(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFLunchBox::UsesPrimaryAmmo( void ) |
|
{ |
|
return CBaseCombatWeapon::UsesPrimaryAmmo(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFLunchBox::DropAllowed( void ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); |
|
if ( pOwner ) |
|
{ |
|
if ( pOwner->m_Shared.InCond( TF_COND_TAUNTING ) ) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::PrimaryAttack( void ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); |
|
if ( !pOwner ) |
|
return; |
|
|
|
if ( !HasAmmo() ) |
|
return; |
|
|
|
#if GAME_DLL |
|
pOwner->Taunt(); |
|
m_flNextPrimaryAttack = pOwner->GetTauntRemoveTime() + 0.1f; |
|
#else |
|
m_flNextPrimaryAttack = gpGlobals->curtime + 2.0f; // this will be corrected by the game server |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::SecondaryAttack( void ) |
|
{ |
|
if ( !DropAllowed() ) |
|
return; |
|
|
|
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() ); |
|
if ( !pPlayer ) |
|
return; |
|
|
|
if ( !HasAmmo() ) |
|
return; |
|
|
|
#ifndef CLIENT_DLL |
|
|
|
if ( m_hThrownPowerup ) |
|
{ |
|
UTIL_Remove( m_hThrownPowerup ); |
|
} |
|
|
|
// Throw out the medikit |
|
Vector vecSrc = pPlayer->EyePosition() + Vector(0,0,-8); |
|
QAngle angForward = pPlayer->EyeAngles() + QAngle(-10,0,0); |
|
|
|
int nLunchBoxType = GetLunchboxType(); |
|
|
|
const char *pszHealthKit; |
|
switch ( nLunchBoxType ) |
|
{ |
|
case LUNCHBOX_ADDS_MAXHEALTH: |
|
pszHealthKit = "item_healthkit_small"; |
|
break; |
|
|
|
case LUNCHBOX_ADDS_AMMO: |
|
pszHealthKit = "item_healthammokit"; |
|
break; |
|
|
|
default: |
|
pszHealthKit = "item_healthkit_medium"; |
|
} |
|
|
|
CHealthKit *pMedKit = assert_cast<CHealthKit*>( CBaseEntity::Create( pszHealthKit, vecSrc, angForward, pPlayer ) ); |
|
|
|
if ( pMedKit ) |
|
{ |
|
Vector vecForward, vecRight, vecUp; |
|
AngleVectors( angForward, &vecForward, &vecRight, &vecUp ); |
|
Vector vecVelocity = vecForward * 500.0; |
|
|
|
if ( nLunchBoxType == LUNCHBOX_ADDS_MINICRITS ) |
|
{ |
|
pMedKit->SetModel( LUNCHBOX_STEAK_DROP_MODEL ); |
|
} |
|
else if ( nLunchBoxType == LUNCHBOX_STANDARD_ROBO ) |
|
{ |
|
pMedKit->SetModel( LUNCHBOX_ROBOT_DROP_MODEL ); |
|
pMedKit->m_nSkin = ( pPlayer->GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1; |
|
} |
|
else if ( nLunchBoxType == LUNCHBOX_STANDARD_FESTIVE ) |
|
{ |
|
pMedKit->SetModel( LUNCHBOX_FESTIVE_DROP_MODEL ); |
|
pMedKit->m_nSkin = ( pPlayer->GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1; |
|
} |
|
else if ( nLunchBoxType == LUNCHBOX_ADDS_MAXHEALTH ) |
|
{ |
|
pMedKit->SetModel( LUNCHBOX_CHOCOLATE_BAR ); |
|
} |
|
else |
|
{ |
|
pMedKit->SetModel( LUNCHBOX_DROP_MODEL ); |
|
} |
|
|
|
// clear out the overrides so the thrown sandvich/steak look correct in either vision mode |
|
pMedKit->ClearModelIndexOverrides(); |
|
|
|
pMedKit->SetAbsAngles( vec3_angle ); |
|
pMedKit->SetSize( LUNCHBOX_DROPPED_MINS, LUNCHBOX_DROPPED_MAXS ); |
|
|
|
// the thrower has to wait 0.3 to pickup the powerup (so he can throw it while running forward) |
|
pMedKit->DropSingleInstance( vecVelocity, pPlayer, 0.3 ); |
|
} |
|
|
|
m_hThrownPowerup = pMedKit; |
|
#endif |
|
|
|
pPlayer->RemoveAmmo( m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_iAmmoPerShot, m_iPrimaryAmmoType ); |
|
g_pGameRules->SwitchToNextBestWeapon( pPlayer, this ); |
|
|
|
StartEffectBarRegen(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::DrainAmmo( bool bForceCooldown ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); |
|
if ( !pOwner ) |
|
return; |
|
|
|
#ifdef GAME_DLL |
|
|
|
int iLunchboxType = GetLunchboxType(); |
|
// If we're damaged while eating/taunting, bForceCooldown will be true |
|
if ( pOwner->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) ) |
|
{ |
|
if ( pOwner->GetHealth() < pOwner->GetMaxHealth() || GetLunchboxType() == LUNCHBOX_ADDS_MINICRITS || iLunchboxType == LUNCHBOX_ADDS_MAXHEALTH || bForceCooldown ) |
|
{ |
|
StartEffectBarRegen(); |
|
} |
|
else // Full health regular sandwhich, I can eat forever |
|
{ |
|
return; |
|
} |
|
} |
|
else if ( pOwner->IsPlayerClass( TF_CLASS_SCOUT ) ) |
|
{ |
|
StartEffectBarRegen(); |
|
} |
|
|
|
// Strange Tracking. Only go through if we have ammo at this point. |
|
if ( !pOwner->IsBot() && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) |
|
{ |
|
EconEntity_OnOwnerKillEaterEventNoPartner( dynamic_cast<CEconEntity *>( this ), pOwner, kKillEaterEvent_FoodEaten ); |
|
} |
|
|
|
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType ); |
|
#else |
|
|
|
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType ); |
|
StartEffectBarRegen(); |
|
|
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::Detach( void ) |
|
{ |
|
#ifdef GAME_DLL |
|
// Terrible - but for now, we're the only place that adds this (custom) attribute |
|
if ( GetLunchboxType() == LUNCHBOX_ADDS_MAXHEALTH ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); |
|
if ( pOwner ) |
|
{ |
|
// Prevents use-then-switch-class exploit (heavy->scout) |
|
// Not a big deal in pubs, but it can mess with competitive |
|
pOwner->RemoveCustomAttribute( "hidden maxhealth non buffed" ); |
|
} |
|
} |
|
#endif |
|
|
|
BaseClass::Detach(); |
|
} |
|
|
|
#ifdef GAME_DLL |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFLunchBox::ApplyBiteEffects( CTFPlayer *pPlayer ) |
|
{ |
|
int nLunchBoxType = GetLunchboxType(); |
|
|
|
if ( nLunchBoxType == LUNCHBOX_ADDS_MAXHEALTH ) |
|
{ |
|
// add 50 health to player for 30 seconds |
|
pPlayer->AddCustomAttribute( "hidden maxhealth non buffed", 50.f, 30.f ); |
|
} |
|
else if ( nLunchBoxType == LUNCHBOX_ADDS_MINICRITS ) |
|
{ |
|
static const float s_fSteakSandwichDuration = 16.0f; |
|
|
|
// Steak sandvich. |
|
pPlayer->m_Shared.AddCond( TF_COND_ENERGY_BUFF, s_fSteakSandwichDuration ); |
|
pPlayer->m_Shared.AddCond( TF_COND_CANNOT_SWITCH_FROM_MELEE, s_fSteakSandwichDuration ); |
|
pPlayer->m_Shared.SetBiteEffectWasApplied(); |
|
|
|
return; |
|
} |
|
|
|
// Then heal the player |
|
int iHeal = ( nLunchBoxType == LUNCHBOX_ADDS_MAXHEALTH ) ? 25 : 75; |
|
int iHealType = DMG_GENERIC; |
|
if ( nLunchBoxType == LUNCHBOX_ADDS_MAXHEALTH && pPlayer->GetHealth() < 400 ) |
|
{ |
|
iHealType = DMG_IGNORE_MAXHEALTH; |
|
iHeal = Min( 25, 400 - pPlayer->GetHealth() ); |
|
} |
|
|
|
float flHealScale = 1.0f; |
|
CALL_ATTRIB_HOOK_FLOAT( flHealScale, lunchbox_healing_scale ); |
|
iHeal = iHeal * flHealScale; |
|
|
|
int iHealed = pPlayer->TakeHealth( iHeal, iHealType ); |
|
|
|
if ( iHealed > 0 ) |
|
{ |
|
CTF_GameStats.Event_PlayerHealedOther( pPlayer, iHealed ); |
|
} |
|
|
|
// Restore ammo if applicable |
|
if ( nLunchBoxType == LUNCHBOX_ADDS_AMMO ) |
|
{ |
|
int maxPrimary = pPlayer->GetMaxAmmo( TF_AMMO_PRIMARY ); |
|
pPlayer->GiveAmmo( maxPrimary * 0.25, TF_AMMO_PRIMARY, true ); |
|
} |
|
} |
|
#endif // GAME_DLL |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Energy Drink |
|
//----------------------------------------------------------------------------- |
|
CTFLunchBox_Drink::CTFLunchBox_Drink() |
|
{ |
|
} |
|
|
|
#ifdef CLIENT_DLL |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFLunchBox_Drink::Holster( CBaseCombatWeapon *pSwitchingTo ) |
|
{ |
|
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); |
|
if ( pOwner && pOwner->IsLocalPlayer() ) |
|
{ |
|
C_BaseEntity *pParticleEnt = pOwner->GetViewModel(0); |
|
if ( pParticleEnt ) |
|
{ |
|
pOwner->StopViewModelParticles( pParticleEnt ); |
|
} |
|
} |
|
|
|
return BaseClass::Holster( pSwitchingTo ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char* CTFLunchBox_Drink::ModifyEventParticles( const char* token ) |
|
{ |
|
if ( GetLunchboxType() == LUNCHBOX_ADDS_MINICRITS ) |
|
{ |
|
if ( FStrEq( token, "energydrink_splash") ) |
|
{ |
|
CEconItemView *pItem = m_AttributeManager.GetItem(); |
|
int iSystems = pItem->GetStaticData()->GetNumAttachedParticles( GetTeamNumber() ); |
|
for ( int i = 0; i < iSystems; i++ ) |
|
{ |
|
attachedparticlesystem_t *pSystem = pItem->GetStaticData()->GetAttachedParticleData( GetTeamNumber(),i ); |
|
if ( pSystem->iCustomType == 1 ) |
|
{ |
|
return pSystem->pszSystemName; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return BaseClass::ModifyEventParticles( token ); |
|
} |
|
|
|
#endif // CLIENT_DLL
|