1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-01-05 17:13:36 +08:00
hl2sdk/game/client/swarm/c_asw_marine_resource.cpp
2010-07-22 01:46:14 -05:00

405 lines
11 KiB
C++

#include "cbase.h"
#include "asw_gamerules.h"
#include "c_asw_marine_resource.h"
#include "asw_marine_profile.h"
#include "c_asw_marine.h"
#include "c_asw_player.h"
#include "c_asw_weapon.h"
#include "asw_weapon_medical_satchel_shared.h"
#include "c_asw_door.h"
#include "c_playerresource.h"
#include <vgui/ILocalize.h>
#include "clientmode_shared.h"
#include "nb_main_panel.h"
#include "c_asw_campaign_save.h"
#include "c_asw_game_resource.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#undef CASW_Marine_Resource
#define CASW_Marine_Resource CASW_Marine_Resource
BEGIN_RECV_TABLE_NOBASE( C_ASW_Marine_Resource, DT_MR_Timelines )
RecvPropDataTable( RECVINFO_DT( m_TimelineFriendlyFire ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
RecvPropDataTable( RECVINFO_DT( m_TimelineKillsTotal ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
RecvPropDataTable( RECVINFO_DT( m_TimelineHealth ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
RecvPropDataTable( RECVINFO_DT( m_TimelineAmmo ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
RecvPropDataTable( RECVINFO_DT( m_TimelinePosX ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
RecvPropDataTable( RECVINFO_DT( m_TimelinePosY ), 0, &REFERENCE_RECV_TABLE(DT_Timeline) ),
END_RECV_TABLE();
IMPLEMENT_CLIENTCLASS_DT(C_ASW_Marine_Resource, DT_ASW_Marine_Resource, CASW_Marine_Resource)
RecvPropDataTable( "mr_timelines", 0, 0, &REFERENCE_RECV_TABLE(DT_MR_Timelines) ),
RecvPropInt (RECVINFO(m_MarineProfileIndex)),
RecvPropEHandle (RECVINFO(m_MarineEntity)),
RecvPropEHandle (RECVINFO(m_Commander)),
RecvPropInt (RECVINFO(m_iCommanderIndex)),
RecvPropArray ( RecvPropInt( RECVINFO(m_iWeaponsInSlots[0]), 30 ), m_iWeaponsInSlots ),
RecvPropBool (RECVINFO(m_bInfested) ),
RecvPropBool (RECVINFO(m_bInhabited) ),
RecvPropInt (RECVINFO(m_iServerFiring) ),
//RecvPropFloat (RECVINFO(m_fDamageTaken) ),
RecvPropInt (RECVINFO(m_iAliensKilled), 16 ),
RecvPropBool (RECVINFO(m_bTakenWoundDamage) ),
RecvPropBool (RECVINFO(m_bHealthHalved) ),
RecvPropString (RECVINFO(m_MedalsAwarded) ),
RecvPropEHandle (RECVINFO(m_hWeldingDoor)),
RecvPropBool (RECVINFO(m_bUsingEngineeringAura) ),
END_RECV_TABLE()
extern ConVar asw_leadership_radius;
extern ConVar asw_skill_healing_charges_base;
extern ConVar asw_skill_healing_charges_step;
C_ASW_Marine_Resource::C_ASW_Marine_Resource()
{
m_MarineProfileIndex = -1;
m_iScannerSoundSkip = 3;
m_fScannerTime = RandomFloat(1.0f, 2.5f);
m_bPlayedBlipSound = false;
m_fFiring = 0;
m_fLastHealthPercent = 0;
m_fHurtPulse = 0;
m_bTakenWoundDamage = 0;
m_fNextLeadershipTest = 0;
m_fLeadershipResist = 0;
m_iServerFiring = 0;
m_fNextMedsCountTime = 0;
m_fCachedMedsPercent = 0;
m_MedalsAwarded[0] = '\0';
m_bUsingEngineeringAura = false;
m_Commander = NULL;
m_iCommanderIndex = -1;
memset( m_iWeaponsInSlots, -1, sizeof( m_iWeaponsInSlots ) );
}
C_ASW_Marine_Resource::~C_ASW_Marine_Resource()
{
}
CASW_Marine_Profile* C_ASW_Marine_Resource::GetProfile(void)
{
if (MarineProfileList() == NULL)
return NULL;
if (m_MarineProfileIndex >=0 && m_MarineProfileIndex < MarineProfileList()->m_NumProfiles)
return MarineProfileList()->m_Profiles[m_MarineProfileIndex];
return NULL;
}
C_ASW_Marine* C_ASW_Marine_Resource::GetMarineEntity()
{
C_BaseEntity* base = m_MarineEntity;
C_ASW_Marine* marine = (C_ASW_Marine*) base;
return marine;
}
C_ASW_Player* C_ASW_Marine_Resource::GetCommander()
{
return dynamic_cast<C_ASW_Player*>(m_Commander.Get());
}
void C_ASW_Marine_Resource::GetDisplayName( char *pchDisplayName, int nMaxBytes )
{
wchar_t wszDisplayName[ 256 ];
GetDisplayName( wszDisplayName, sizeof( wszDisplayName ) );
g_pVGuiLocalize->ConvertUnicodeToANSI( wszDisplayName, pchDisplayName, nMaxBytes );
}
void C_ASW_Marine_Resource::GetDisplayName( wchar_t *pwchDisplayName, int nMaxBytes )
{
bool bPlayerName = false;
const char *pchName = NULL;
if ( gpGlobals->maxClients <= 1 )
{
// Always use the character name in singleplayer
pchName = GetProfile()->GetShortName();
}
else
{
bool bIsInhabited = IsInhabited();
if ( bIsInhabited && GetCommander() && g_PR->IsConnected( m_iCommanderIndex ) )
{
// Use the player name
pchName = g_PR->GetPlayerName( m_iCommanderIndex );
bPlayerName = true;
}
else
{
// Use the character name
pchName = GetProfile()->GetShortName();
}
}
const wchar_t *pwchLocalizedMarineName = NULL;
if ( !bPlayerName )
{
// Find the localized character name
pwchLocalizedMarineName = g_pVGuiLocalize->Find( pchName );
}
if ( pwchLocalizedMarineName )
{
// Copy the localized name
Q_wcsncpy( pwchDisplayName, pwchLocalizedMarineName, nMaxBytes );
}
else
{
// Copy the name
g_pVGuiLocalize->ConvertANSIToUnicode( pchName, pwchDisplayName, nMaxBytes );
}
}
// accessors for the HUD portraits
// NOTE: Currently we're assuming marine entities are always transmitted to clients
// and this code relies on that. In the future we may want to instead periodically transmit this info
// through this entity and not rely on the marine entity itself.
float C_ASW_Marine_Resource::GetHealthPercent()
{
C_ASW_Marine *marine = GetMarineEntity();
if (!marine)
return 0;
float max_health = marine->GetMaxHealth();
if ( max_health <= 0 )
return 0;
float health = marine->GetHealth();
return clamp(health / max_health, 0.0f, 1.0f);
}
float C_ASW_Marine_Resource::GetInfestedPercent()
{
C_ASW_Marine *marine = GetMarineEntity();
if (!marine || !ASWGameRules() || !IsInfested())
return 0;
float max_health = marine->GetMaxHealth();
float fInfestedDamage = (ASWGameRules()->TotalInfestDamage() / 20.0f) * marine->m_fInfestedTime;
fInfestedDamage *= MIN( gpGlobals->curtime - marine->m_fInfestedStartTime, 15.0f ) / 15.0f;
float fPercent = fInfestedDamage / max_health;
return fPercent * fPercent;
}
float C_ASW_Marine_Resource::GetAmmoPercent()
{
C_ASW_Marine *marine = GetMarineEntity();
if (!marine)
return 0;
C_ASW_Weapon *weapon = marine->GetActiveASWWeapon();
if (!weapon)
return 0;
float max_ammo = weapon->GetMaxClip1();
float ammo = weapon->Clip1(); // ammo inside the gun
return clamp( ammo / max_ammo, 0.0f, 1.0f );
}
float C_ASW_Marine_Resource::GetClipsPercent()
{
C_ASW_Marine *marine = GetMarineEntity();
if (!marine)
return 0;
C_ASW_Weapon *weapon = marine->GetActiveASWWeapon();
if (!weapon)
return 0;
float max_clips = 8;
int clips = marine->GetAmmoCount(weapon->GetPrimaryAmmoType()); // ammo the marine is carrying outside the gun
clips /= weapon->GetMaxClip1(); // divide it down to get the number of clips
float fResult = clips / max_clips;
if (fResult > 1)
fResult = 1.0f;
return fResult;
}
float C_ASW_Marine_Resource::GetMedsPercent()
{
if (gpGlobals->curtime < m_fNextMedsCountTime)
{
return m_fCachedMedsPercent;
}
C_ASW_Marine *pMarine = GetMarineEntity();
if ( !pMarine )
return 0;
int meds = 0;
for ( int i = 0; i < ASW_NUM_INVENTORY_SLOTS; i++ )
{
C_BaseCombatWeapon *pWeapon = pMarine->GetWeapon( i );
if ( pWeapon && ( pWeapon->Classify() == CLASS_ASW_MEDICAL_SATCHEL
|| pWeapon->Classify() == CLASS_ASW_HEALGRENADE ) )
{
meds+= pWeapon->Clip1();
}
}
float max_meds = asw_skill_healing_charges_base.GetInt() + ( asw_skill_healing_charges_step.GetInt() * 5 );
m_fCachedMedsPercent = float( meds ) / float( max_meds );
if ( m_fCachedMedsPercent > 1 )
m_fCachedMedsPercent = 1.0f;
m_fNextMedsCountTime = gpGlobals->curtime + 0.5f;
return m_fCachedMedsPercent;
}
bool C_ASW_Marine_Resource::IsFiring()
{
// if we can directly see the marine and his weapon, then check accurately if he's firing
//if (GetMarineEntity() && GetMarineEntity()->GetActiveASWWeapon() && !GetMarineEntity()->GetActiveASWWeapon()->IsDormant())
//{
//return GetMarineEntity()->GetActiveASWWeapon()->IsFiring();
//}
// if not, then see what the server says
return (m_iServerFiring > 0);
}
// countdown timer for our firing
float C_ASW_Marine_Resource::GetFiringTimer()
{
return m_fFiring;
}
void C_ASW_Marine_Resource::OnDataChanged(DataUpdateType_t updateType)
{
if ( updateType == DATA_UPDATE_CREATED )
{
FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
if (pPlayer && pPlayer == GetCommander() && ASWGameRules() && ASWGameRules()->GetGameState() <= ASW_GS_BRIEFING)
{
// we're in briefing and a marine has just been selected by us (possibly autoselection)
// send our last saved loadout
pPlayer->LoadoutSendStored(this);
// see if we need to spend skill points
if ( ASWGameRules()->IsCampaignGame() && ASWGameRules()->GetCampaignSave() && !ASWGameRules()->GetCampaignSave()->UsingFixedSkillPoints()
&& ASWGameResource() && ASWGameResource()->GetMarineSkill( this, ASW_SKILL_SLOT_SPARE ) > 0 )
{
CNB_Main_Panel::QueueSpendSkillPoints( GetProfileIndex() );
}
}
}
SetNextClientThink(gpGlobals->curtime);
}
BaseClass::OnDataChanged(updateType);
}
void C_ASW_Marine_Resource::ClientThink()
{
if (GetHealthPercent() <= 0)
{
m_fFiring = 0;
}
else
{
if (m_iServerFiring == 2) // firing a slow firing shotgun/pistol type weapon
{
float fFireScale = 1.0f;
//C_ASW_Marine *pMarine = GetMarineEntity();
//if (pMarine)
//{
//C_ASW_Weapon *pWeapon = pMarine->GetActiveASWWeapon();
//if (pWeapon)
//{
//float fRate = pWeapon->GetFireRate();
//// scale our rate of decay according to the firing rate of the gun
//if (fRate > 0)
//fFireScale = 0.8f / fRate;
//}
//}
if (m_fFiring > 0)
{
m_fFiring = MAX(m_fFiring - gpGlobals->frametime * fFireScale, 0); //0.8 seconds to fade out with firescale of 1
}
if (m_fFiring <= 0)
m_fFiring += 0.8;
}
else
{
if (m_fFiring > 0)
{
m_fFiring = MAX(m_fFiring - gpGlobals->frametime, 0);
}
if (m_iServerFiring == 1) // firing a rapid fire machine gun type weapon
{
m_fFiring = random->RandomFloat(0.5, 1.0f);
}
}
}
// tick down a value used for flashing the marine red when hurt
if (m_fHurtPulse > 0)
{
m_fHurtPulse -= gpGlobals->frametime * 2;
if (m_fHurtPulse < 0)
m_fHurtPulse = 0;
}
float flHealth = GetHealthPercent();
if ( flHealth < m_fLastHealthPercent )
{
m_fHurtPulse = 1.0f;
}
m_fLastHealthPercent = flHealth;
if (gpGlobals->curtime > m_fNextLeadershipTest)
{
UpdateLeadershipBonus();
}
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
void C_ASW_Marine_Resource::UpdateLeadershipBonus()
{
if (GetMarineEntity() && GetHealthPercent() > 0)
{
m_fLeadershipResist = MarineSkills()->GetHighestSkillValueNearby(GetMarineEntity()->GetAbsOrigin(),
asw_leadership_radius.GetFloat(),
ASW_MARINE_SKILL_LEADERSHIP, ASW_MARINE_SUBSKILL_LEADERSHIP_DAMAGE_RESIST);
m_fNextLeadershipTest = gpGlobals->curtime + 0.5f;
}
else
{
m_fNextLeadershipTest = gpGlobals->curtime + 2.0f;
}
}
// note: assumes marine entity is networked to all clients...
bool C_ASW_Marine_Resource::IsReloading()
{
if (!GetMarineEntity())
return false;
C_ASW_Weapon *pWeapon = GetMarineEntity()->GetActiveASWWeapon();
if (!pWeapon)
return false;
return pWeapon->IsReloading();
}