|
|
//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "buy_preset_debug.h"
#include "buy_presets.h"
#include "weapon_csbase.h"
#include "cs_ammodef.h"
#include "cs_gamerules.h"
#include "c_cs_player.h"
#include "bot/shared_util.h"
#include "vgui/ILocalize.h"
#include <vgui_controls/Controls.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar cl_rebuy;
extern CSWeaponID GetClientWeaponID( bool primary );
//--------------------------------------------------------------------------------------------------------------
/**
* Returns true if the local player is a CT and the map is a defuse map. */ static bool CanBuyDefuser() { C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); return ( pPlayer && pPlayer->GetTeamNumber() == TEAM_CT && CSGameRules()->IsBombDefuseMap() ); }
void BuyPresetManager::GetCurrentLoadout( WeaponSet *weaponSet ) { if ( !weaponSet ) return;
C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer(); if ( !player ) return;
CWeaponCSBase *pWeapon; const CCSWeaponInfo *pInfo;
int ammo[MAX_AMMO_TYPES]; memset( ammo, 0, sizeof(ammo) ); FillClientAmmo( ammo );
weaponSet->Reset();
// Grab current armor values
weaponSet->m_armor = ( player->ArmorValue() > 0 ) ? 100 : 0; weaponSet->m_helmet = player->HasHelmet();
// Grab current smoke grenade
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_SMOKEGRENADE )); pInfo = GetWeaponInfo( WEAPON_SMOKEGRENADE ); int ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0; weaponSet->m_smokeGrenade = (pWeapon && player->GetAmmoCount( ammoType ));
// Grab current HE grenade
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_HEGRENADE )); pInfo = GetWeaponInfo( WEAPON_HEGRENADE ); ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0; weaponSet->m_HEGrenade = (pWeapon && player->GetAmmoCount( ammoType ));
// Grab current flashbangs
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_FLASHBANG )); pInfo = GetWeaponInfo( WEAPON_FLASHBANG ); ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0; weaponSet->m_flashbangs = (!pWeapon) ? 0 : player->GetAmmoCount( ammoType );
// Grab current equipment
weaponSet->m_defuser = player->HasDefuser(); weaponSet->m_nightvision = player->HasNightVision();
// Grab current primary weapon
CSWeaponID primaryID = GetClientWeaponID( true ); ///< The local player's current primary weapon
pInfo = GetWeaponInfo( primaryID ); if ( pInfo ) { int roundsNeeded = ammo[pInfo->GetPrimaryAmmoType()]; int buySize = GetCSAmmoDef()->GetBuySize( pInfo->GetPrimaryAmmoType() ); int numClips = ceil(roundsNeeded/(float)buySize);
weaponSet->m_primaryWeapon.SetWeaponID( primaryID ); weaponSet->m_primaryWeapon.SetAmmoType( AMMO_CLIPS ); weaponSet->m_primaryWeapon.SetAmmoAmount( numClips ); weaponSet->m_primaryWeapon.SetFillAmmo( false ); }
// Grab current pistol
CSWeaponID secondaryID = GetClientWeaponID( false ); ///< The local player's current pistol
pInfo = GetWeaponInfo( secondaryID ); if ( pInfo ) { int roundsNeeded = ammo[pInfo->GetPrimaryAmmoType()]; int buySize = GetCSAmmoDef()->GetBuySize( pInfo->GetPrimaryAmmoType() ); int numClips = ceil(roundsNeeded/(float)buySize);
weaponSet->m_secondaryWeapon.SetWeaponID( secondaryID ); weaponSet->m_secondaryWeapon.SetAmmoType( AMMO_CLIPS ); weaponSet->m_secondaryWeapon.SetAmmoAmount( numClips ); weaponSet->m_secondaryWeapon.SetFillAmmo( false ); } }
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
WeaponSet::WeaponSet() { Reset(); }
//--------------------------------------------------------------------------------------------------------------
/**
* Sets reasonable defaults for an empty weapon set: no primary/secondary weapons, no equipment, and * everything optional. */ void WeaponSet::Reset() { BuyPresetWeapon blank; m_primaryWeapon = blank; m_secondaryWeapon = blank;
m_armor = 0; m_helmet = false; m_smokeGrenade = false; m_HEGrenade = false; m_flashbangs = 0; m_defuser = false; m_nightvision = false; }
//--------------------------------------------------------------------------------------------------------------
/**
* Constructs a WeaponSet containing everything that could be purchased right now. The cost is also * returned, and is -1 if the set is not purchasable (as opposed to completely purchased already, in * which case cost is 0.) */ void WeaponSet::GetCurrent( int& cost, WeaponSet& ws ) const { cost = -1; ws.Reset();
if ( !engine->IsConnected() ) return;
C_CSPlayer *player = CCSPlayer::GetLocalCSPlayer(); if ( !player ) return;
if ( player->GetTeamNumber() != TEAM_CT && player->GetTeamNumber() != TEAM_TERRORIST ) return;
// we're connected, and a valid team, so we can purchase
cost = 0;
if ( player->IsVIP() ) return; // can't buy anything as the VIP
int iHelmetPrice = ITEM_PRICE_HELMET; int iKevlarPrice = ITEM_PRICE_KEVLAR; int iNVGPrice = ITEM_PRICE_NVG;
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Buy any required items
//-------------------------------------------------------------------------
// Armor
if ( m_armor > player->ArmorValue() ) { cost += iKevlarPrice; ws.m_armor = 100; }
if ( (m_helmet && m_armor > 0) && !player->HasHelmet() ) { cost += iHelmetPrice; ws.m_armor = 100; ws.m_helmet = true; }
CWeaponCSBase *pWeapon; const CCSWeaponInfo *pInfo;
//-------------------------------------------------------------------------
// Smoke grenade
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_SMOKEGRENADE )); pInfo = GetWeaponInfo( WEAPON_SMOKEGRENADE ); int ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0;
bool hasSmokeGrenade = (pWeapon && player->GetAmmoCount( ammoType )); if ( m_smokeGrenade && !hasSmokeGrenade ) { cost += pWeapon->GetWeaponPrice(); ws.m_smokeGrenade = true; hasSmokeGrenade = true; }
//-------------------------------------------------------------------------
// HE grenade
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_HEGRENADE )); pInfo = GetWeaponInfo( WEAPON_HEGRENADE ); ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0;
bool hasHEGrenade = (pWeapon && player->GetAmmoCount( ammoType )); if ( m_HEGrenade && !hasHEGrenade ) { cost += pWeapon->GetWeaponPrice(); ws.m_HEGrenade = true; hasHEGrenade = true; }
//-------------------------------------------------------------------------
// Flashbang grenades
pWeapon = dynamic_cast< CWeaponCSBase * >(player->GetCSWeapon( WEAPON_FLASHBANG )); pInfo = GetWeaponInfo( WEAPON_FLASHBANG ); ammoType = (pInfo)?pInfo->GetPrimaryAmmoType():0;
int numFlashbangs = (!pWeapon) ? 0 : player->GetAmmoCount( ammoType ); if ( m_flashbangs && numFlashbangs < m_flashbangs ) { int count = m_flashbangs - numFlashbangs; cost += pWeapon->GetWeaponPrice() * count; ws.m_flashbangs = count; numFlashbangs += count; }
//-------------------------------------------------------------------------
// defuser
if ( m_defuser && player->GetTeamNumber() == TEAM_CT && !player->HasDefuser() && CanBuyDefuser() ) { cost += ITEM_PRICE_DEFUSEKIT; ws.m_defuser = true; }
//-------------------------------------------------------------------------
// nightvision goggles
if ( m_nightvision && !player->HasNightVision() ) { cost += iNVGPrice; ws.m_nightvision = true; }
//-------------------------------------------------------------------------
// Construct a list of weapons to buy from.
CSWeaponID primaryID = GetClientWeaponID( true ); ///< The local player's current primary weapon
CSWeaponID secondaryID = GetClientWeaponID( false ); ///< The local player's current pistol
BuyPresetWeaponList primaryWeapons; primaryWeapons.AddToTail( m_primaryWeapon );
BuyPresetWeaponList secondaryWeapons; secondaryWeapons.AddToTail( m_secondaryWeapon );
/**
* Determine best weapons & ammo to purchase * * For each primary weapon in the list, do the following until one satisfies the current money situation: * 1. buy primary weapon and its ammo (NEED TO WATCH FOR WEAPONS PLAYER CANNOT BUY!!!) * 2. for each non-optional secondary weapon (if any), * try to buy it and its ammo * 3. when a set can be purchased, add it to the total cost and stop processing * If we can't purchase the primary weapon, or a required secondary weapon, the WeaponSet can't be bought, * so we return -1. * * To find if a weapon is owned, we can compare it's weaponID to either primaryID or secondaryID from above. */
int currentCost = cost; int ammo[MAX_AMMO_TYPES]; memset( ammo, 0, sizeof(ammo) ); FillClientAmmo( ammo ); const BuyPresetWeapon *primaryWeaponToBuy = NULL; const BuyPresetWeapon *secondaryWeaponToBuy = NULL; int primaryClipsToBuy = 0; int secondaryClipsToBuy = 0; int currentNonWeaponCost = currentCost; bool doneBuyingWeapons = false;
int currentCash = player->GetAccount();
//-------------------------------------------------------------------------
// Try to buy the primary weapon
int i; for ( i=0; i<primaryWeapons.Count() && !doneBuyingWeapons; ++i ) { const BuyPresetWeapon *primaryWeapon = &primaryWeapons[i]; primaryWeaponToBuy = NULL; int primaryClips = 0; primaryClipsToBuy = 0; currentCost = currentNonWeaponCost; FillClientAmmo( ammo );
CSWeaponID weaponID = primaryWeapon->GetCSWeaponID(); if ( weaponID == WEAPON_NONE ) weaponID = primaryID;
const CCSWeaponInfo *primaryInfo = GetWeaponInfo( weaponID ); int primaryAmmoCost = 0; int primaryAmmoBuySize = 0; if ( primaryInfo ) { primaryClips = CalcClipsNeeded( primaryWeapon, primaryInfo, ammo ); int primaryWeaponCost = ( weaponID != primaryID ) ? primaryInfo->GetWeaponPrice() : 0; primaryAmmoCost = GetCSAmmoDef()->GetCost( primaryInfo->GetPrimaryAmmoType() ); primaryAmmoBuySize = GetCSAmmoDef()->GetBuySize( primaryInfo->GetPrimaryAmmoType() ); currentCost += primaryWeaponCost; currentCost += primaryAmmoCost * primaryClips; ammo[primaryInfo->GetPrimaryAmmoType()] += primaryClips * primaryAmmoBuySize;
CURRENTCOST_DEBUG("\t%5.5d (%s)\n", primaryWeaponCost, WeaponIDToAlias( weaponID )); CURRENTCOST_DEBUG("\t%5.5d (ammo x %d)\n", primaryAmmoCost * primaryClips, primaryClips); if ( currentCash < currentCost ) { currentCost = currentNonWeaponCost; // can't afford it, so try the next weapon
continue; }
// check for as_* maps, and CTs buying AK47s, etc
if ( !CanBuyWeapon(primaryID, secondaryID, weaponID) && weaponID != primaryID ) { currentCost = currentNonWeaponCost; // can't buy it, so try the next weapon
continue; }
primaryWeaponToBuy = primaryWeapon; primaryClipsToBuy = primaryClips; }
if ( !secondaryWeapons.Count() ) { CURRENTCOST_DEBUG("\t\t\tDone buying weapons (no secondary)\n"); break; }
//-------------------------------------------------------------------------
// Try to buy a (required) secondary weapon to go with primaryWeaponToBuy.
// If not, reset cost to not reflect either weapon, so we can look at buying
// the next primary weapon in the list.
int j; for ( j=0; j<secondaryWeapons.Count(); ++j ) { const BuyPresetWeapon *secondaryWeapon = &secondaryWeapons[j];
// reset ammo counts and cost
secondaryWeaponToBuy = NULL; secondaryClipsToBuy = 0; currentCost = currentNonWeaponCost; FillClientAmmo( ammo );
// add in ammo we're already buying for the primary weapon to the client's actual ammo
if ( primaryInfo ) { currentCost += ( weaponID != primaryID ) ? primaryInfo->GetWeaponPrice() : 0; currentCost += primaryAmmoCost * primaryClips; ammo[primaryInfo->GetPrimaryAmmoType() ] += primaryClips * primaryAmmoBuySize; }
int currentCostWithoutSecondary = currentCost;
CSWeaponID weaponID = secondaryWeapon->GetCSWeaponID(); if ( weaponID == WEAPON_NONE ) weaponID = secondaryID;
const CCSWeaponInfo *secondaryInfo = GetWeaponInfo( weaponID ); if ( !secondaryInfo ) { currentCost = currentCostWithoutSecondary; continue; }
int secondaryClips = CalcClipsNeeded( secondaryWeapon, secondaryInfo, ammo ); int secondaryWeaponCost = ( weaponID != secondaryID ) ? secondaryInfo->GetWeaponPrice() : 0; int secondaryAmmoCost = GetCSAmmoDef()->GetCost( secondaryInfo->GetPrimaryAmmoType() ); int secondaryAmmoBuySize = GetCSAmmoDef()->GetBuySize( secondaryInfo->GetPrimaryAmmoType() ); currentCost += secondaryWeaponCost; currentCost += secondaryAmmoCost * secondaryClips; ammo[secondaryInfo->GetPrimaryAmmoType() ] += secondaryClips * secondaryAmmoBuySize;
CURRENTCOST_DEBUG("\t%5.5d (%s)\n", secondaryWeaponCost, WeaponIDToAlias( weaponID )); CURRENTCOST_DEBUG("\t%5.5d (ammo x %d)\n", secondaryAmmoCost * secondaryClips, secondaryClips); if ( currentCash < currentCost ) { currentCost = currentCostWithoutSecondary; // can't afford it, so skip
continue; }
// check for as_* maps, and CTs buying elites, etc
if ( !CanBuyWeapon(primaryID, secondaryID, weaponID) && weaponID != secondaryID ) { currentCost = currentCostWithoutSecondary; // can't buy it, so skip
continue; }
// We found both a primary and secondary weapon to buy. Stop looking for more.
secondaryWeaponToBuy = secondaryWeapon; secondaryClipsToBuy = secondaryClips; doneBuyingWeapons = true; CURRENTCOST_DEBUG("\t\t\tDone buying weapons (primary && secondary)\n"); break; } }
// Update our cost to reflect the weapons and ammo purchased
cost = currentCost;
if ( primaryWeaponToBuy ) { BuyPresetWeapon weapon = *primaryWeaponToBuy; weapon.SetAmmoAmount( primaryClipsToBuy ); weapon.SetAmmoType( AMMO_CLIPS ); ws.m_primaryWeapon = weapon; } else { // If we failed to buy a primary weapon, and one was in the list, bail - the player can't afford this WeaponSet.
for ( int i=0; i<primaryWeapons.Count(); ++i ) { int weaponID = primaryWeapons[i].GetCSWeaponID(); if ( weaponID != WEAPON_NONE ) { cost = -1; ws.Reset(); return; } } }
if ( secondaryWeaponToBuy ) { BuyPresetWeapon weapon = *secondaryWeaponToBuy; weapon.SetAmmoAmount( secondaryClipsToBuy ); weapon.SetAmmoType( AMMO_CLIPS ); ws.m_secondaryWeapon = weapon; } else { // If we failed to buy a required secondary weapon, and one was in the list, bail - the player can't afford this WeaponSet.
for ( int i=0; i<secondaryWeapons.Count(); ++i ) { int weaponID = secondaryWeapons[i].GetCSWeaponID(); if ( weaponID != WEAPON_NONE ) { cost = -1; ws.Reset(); return; } } }
//-------------------------------------------------------------------------
// now any extra ammo, in rebuy order
const char *remainder = SharedParse( cl_rebuy.GetString() ); const char *token;
while ( remainder ) { token = SharedGetToken(); if ( !token || !*token ) return;
if ( !stricmp( token, "PrimaryAmmo" ) ) { if ( primaryWeaponToBuy ) { CSWeaponID id = primaryWeaponToBuy->GetCSWeaponID(); if ( id == WEAPON_NONE ) id = primaryID;
if ( primaryWeaponToBuy->GetFillAmmo() ) { const CCSWeaponInfo *info = GetWeaponInfo( id ); if ( info ) { int maxRounds = GetCSAmmoDef()->MaxCarry( info->GetPrimaryAmmoType(), C_CSPlayer::GetLocalCSPlayer() ); int ammoCost = GetCSAmmoDef()->GetCost( info->GetPrimaryAmmoType() ); int ammoBuySize = GetCSAmmoDef()->GetBuySize( info->GetPrimaryAmmoType() ); int roundsLeft = maxRounds - ammo[info->GetPrimaryAmmoType()]; int clipsLeft = (ammoBuySize > 0) ? ceil(roundsLeft / (float)ammoBuySize) : 0; while ( clipsLeft > 0 && cost + ammoCost <= currentCash ) { ws.m_primaryWeapon.SetAmmoAmount( ws.m_primaryWeapon.GetAmmoAmount() + 1 ); --clipsLeft; ammo[info->GetPrimaryAmmoType()] += MIN(maxRounds, ammoBuySize); cost += ammoCost; } } } } } else if ( !stricmp( token, "SecondaryAmmo" ) ) { if ( secondaryWeaponToBuy ) { if ( secondaryWeaponToBuy->GetFillAmmo() ) { CSWeaponID weaponID = secondaryWeaponToBuy->GetCSWeaponID(); if ( weaponID == WEAPON_NONE ) weaponID = secondaryID;
const CCSWeaponInfo *info = GetWeaponInfo( weaponID ); if ( info ) { int maxRounds = GetCSAmmoDef()->MaxCarry( info->GetPrimaryAmmoType(), C_CSPlayer::GetLocalCSPlayer() ); int ammoCost = GetCSAmmoDef()->GetCost( info->GetPrimaryAmmoType() ); int ammoBuySize = GetCSAmmoDef()->GetBuySize( info->GetPrimaryAmmoType() ); int roundsLeft = maxRounds - ammo[info->GetPrimaryAmmoType() ]; int clipsLeft = (ammoBuySize > 0) ? ceil(roundsLeft / (float)ammoBuySize) : 0; while ( clipsLeft > 0 && cost + ammoCost <= currentCash ) { ws.m_secondaryWeapon.SetAmmoAmount( ws.m_secondaryWeapon.GetAmmoAmount() + 1 ); --clipsLeft; ammo[info->GetPrimaryAmmoType() ] += MIN(maxRounds, ammoBuySize); cost += ammoCost; } } } } }
remainder = SharedParse( remainder ); }
if ( cost > currentCash ) { cost = -1; // can't buy it
ws.Reset(); } }
//--------------------------------------------------------------------------------------------------------------
/**
* Constructs a WeaponSet containing everything that can be purchased. * The cost (including extra cash) is also calculated and returned. */ void WeaponSet::GetFromScratch( int& cost, WeaponSet& ws ) const { cost = 0; ws.Reset();
int ammo[MAX_AMMO_TYPES]; memset( ammo, 0, sizeof(ammo) );
int iHelmetPrice = ITEM_PRICE_HELMET; int iKevlarPrice = ITEM_PRICE_KEVLAR; int iNVGPrice = ITEM_PRICE_NVG;
//-------------------------------------------------------------------------
// Primary weapon
const CCSWeaponInfo *primaryInfo = GetWeaponInfo( m_primaryWeapon.GetCSWeaponID() ); if ( primaryInfo ) { int primaryClips = CalcClipsNeeded( &m_primaryWeapon, primaryInfo, ammo ); int primaryWeaponCost = primaryInfo->GetWeaponPrice(); int primaryAmmoCost = GetCSAmmoDef()->GetCost( primaryInfo->GetPrimaryAmmoType() ); int primaryAmmoBuySize = GetCSAmmoDef()->GetBuySize( primaryInfo->GetPrimaryAmmoType() ); cost += primaryWeaponCost; cost += primaryAmmoCost * primaryClips; ammo[primaryInfo->GetPrimaryAmmoType()] += primaryClips * primaryAmmoBuySize;
ws.m_primaryWeapon = m_primaryWeapon; ws.m_primaryWeapon.SetAmmoAmount( primaryClips ); ws.m_primaryWeapon.SetAmmoType( AMMO_CLIPS ); ws.m_primaryWeapon.SetFillAmmo( false ); }
//-------------------------------------------------------------------------
// secondary weapon
const CCSWeaponInfo *secondaryInfo = GetWeaponInfo( m_secondaryWeapon.GetCSWeaponID() ); if ( secondaryInfo ) { int secondaryClips = CalcClipsNeeded( &m_secondaryWeapon, secondaryInfo, ammo ); int secondaryWeaponCost = secondaryInfo->GetWeaponPrice(); int secondaryAmmoCost = GetCSAmmoDef()->GetCost( secondaryInfo->GetPrimaryAmmoType() ); int secondaryAmmoBuySize = GetCSAmmoDef()->GetBuySize( secondaryInfo->GetPrimaryAmmoType() ); cost += secondaryWeaponCost; cost += secondaryAmmoCost * secondaryClips; ammo[ secondaryInfo->GetPrimaryAmmoType() ] += secondaryClips * secondaryAmmoBuySize;
ws.m_secondaryWeapon = m_secondaryWeapon; ws.m_secondaryWeapon.SetAmmoAmount( secondaryClips ); ws.m_secondaryWeapon.SetAmmoType( AMMO_CLIPS ); ws.m_secondaryWeapon.SetFillAmmo( false ); }
//-------------------------------------------------------------------------
// equipment
if ( m_armor ) { cost += (m_helmet) ? (iKevlarPrice + iHelmetPrice) : iKevlarPrice; ws.m_armor = m_armor; ws.m_helmet = m_helmet; }
if ( m_smokeGrenade ) { const CCSWeaponInfo *pInfo = GetWeaponInfo( WEAPON_SMOKEGRENADE ); cost += ( pInfo ) ? pInfo->GetWeaponPrice() : 0; ws.m_smokeGrenade = m_smokeGrenade; }
if ( m_HEGrenade ) { const CCSWeaponInfo *pInfo = GetWeaponInfo( WEAPON_HEGRENADE ); cost += ( pInfo ) ? pInfo->GetWeaponPrice() : 0; ws.m_HEGrenade = m_HEGrenade; }
const CCSWeaponInfo *pInfo = GetWeaponInfo( WEAPON_FLASHBANG ); cost += ( pInfo ) ? pInfo->GetWeaponPrice() * m_flashbangs : 0; ws.m_flashbangs = m_flashbangs;
if ( m_defuser ) { cost += ITEM_PRICE_DEFUSEKIT; ws.m_defuser = m_defuser; }
if ( m_nightvision ) { cost += iNVGPrice; ws.m_nightvision = m_nightvision; } }
//--------------------------------------------------------------------------------------------------------------
/**
* Convenience function that wraps GetFromScratch() and discards the generated WeaponSet. Returns the cost * to buy the full WeaponSet from scratch. */ int WeaponSet::FullCost() const { WeaponSet fullSet; int cost = 0; GetFromScratch( cost, fullSet ); return cost; }
//--------------------------------------------------------------------------------------------------------------
/**
* Generates a list of buy commands that will buy the current WeaponSet. */ void WeaponSet::GenerateBuyCommands( char command[BUY_PRESET_COMMAND_LEN] ) const { command[0] = 0; char *tmp = command; int remainder = BUY_PRESET_COMMAND_LEN; int i;
CSWeaponID primaryID = GetClientWeaponID( true ); ///< The local player's current primary weapon
CSWeaponID secondaryID = GetClientWeaponID( false ); ///< The local player's current pistol
//-------------------------------------------------------------------------
// Primary weapon
CSWeaponID weaponID = m_primaryWeapon.GetCSWeaponID(); if ( weaponID == WEAPON_NONE ) weaponID = primaryID; const CCSWeaponInfo *primaryInfo = GetWeaponInfo( weaponID ); if ( primaryInfo ) { if ( weaponID != primaryID ) { tmp = BufPrintf( tmp, remainder, "buy %s\n", WeaponIDToAlias(weaponID) ); } for ( i=0; i<m_primaryWeapon.GetAmmoAmount(); ++i ) { tmp = BufPrintf( tmp, remainder, "buyammo1\n" ); } }
//-------------------------------------------------------------------------
// secondary weapon
weaponID = m_secondaryWeapon.GetCSWeaponID(); if ( weaponID == WEAPON_NONE ) weaponID = secondaryID; const CCSWeaponInfo *secondaryInfo = GetWeaponInfo( weaponID ); if ( secondaryInfo ) { if ( weaponID != secondaryID ) { tmp = BufPrintf( tmp, remainder, "buy %s\n", WeaponIDToAlias(weaponID) ); } for ( i=0; i<m_secondaryWeapon.GetAmmoAmount(); ++i ) { tmp = BufPrintf( tmp, remainder, "buyammo2\n" ); } }
//-------------------------------------------------------------------------
// equipment
if ( m_armor ) { if ( m_helmet ) { tmp = BufPrintf( tmp, remainder, "buy vesthelm\n" ); } else { tmp = BufPrintf( tmp, remainder, "buy vest\n" ); } }
if ( m_smokeGrenade ) { tmp = BufPrintf( tmp, remainder, "buy smokegrenade\n" ); }
if ( m_HEGrenade ) { tmp = BufPrintf( tmp, remainder, "buy hegrenade\n" ); }
for ( i=0; i<m_flashbangs; ++i ) { tmp = BufPrintf( tmp, remainder, "buy flashbang\n" ); }
if ( m_defuser ) { tmp = BufPrintf( tmp, remainder, "buy defuser\n" ); }
if ( m_nightvision ) { tmp = BufPrintf( tmp, remainder, "buy nvgs\n" ); } }
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
BuyPreset::BuyPreset() { SetName( L"" ); }
//--------------------------------------------------------------------------------------------------------------
BuyPreset::BuyPreset( const BuyPreset& other ) { *this = other; }
//--------------------------------------------------------------------------------------------------------------
BuyPreset::~BuyPreset() { }
//--------------------------------------------------------------------------------------------------------------
void BuyPreset::SetName( const wchar_t *name ) { wcsncpy( m_name, name, MaxBuyPresetName ); if ( m_name[0] == 0 ) { const wchar_t * defaultName = g_pVGuiLocalize->Find( "#Cstrike_BuyPresetBlank" ); if ( defaultName ) { wcsncpy( m_name, defaultName, MaxBuyPresetName ); } } m_name[MaxBuyPresetName-1] = 0; }
//--------------------------------------------------------------------------------------------------------------
// Parse KeyValues string into a BuyPresetWeapon vector
static void ParseWeaponString( const char *str, BuyPresetWeaponList& weapons, bool isPrimary ) { weapons.RemoveAll();
if ( !str ) return;
const char *remainder = SharedParse( str ); const char *token;
const int BufLen = 32; char tmpBuf[BufLen]; char weaponBuf[BufLen]; char clipModifier; int numClips;
while ( remainder ) { token = SharedGetToken(); if ( !token || strlen(token) >= BufLen ) return;
Q_strncpy( tmpBuf, token, BufLen ); tmpBuf[BufLen - 1] = 0; char *tmp = tmpBuf; while ( *tmp ) { if ( *tmp == '/' ) { *tmp = ' '; } ++tmp; } // sscanf is safe, since the size of the string being scanned is at least as small as any individual destination buffer
if ( sscanf( tmpBuf, "%s %d%c", weaponBuf, &numClips, &clipModifier ) != 3 ) return;
CSWeaponID weaponID = AliasToWeaponID( weaponBuf ); if ( weaponID != WEAPON_NONE ) { const CCSWeaponInfo *info = GetWeaponInfo( weaponID ); if ( info ) { int maxRounds = GetCSAmmoDef()->MaxCarry( info->GetPrimaryAmmoType(), C_CSPlayer::GetLocalCSPlayer() ); int buySize = GetCSAmmoDef()->GetBuySize( info->GetPrimaryAmmoType() ); numClips = MIN(ceil(maxRounds/(float)buySize), MAX(0, numClips)); if ( ((!isPrimary) ^ IsPrimaryWeapon( weaponID )) == 0 ) return; } else { numClips = MIN(NUM_CLIPS_FOR_CURRENT, MAX(0, numClips)); } } else { numClips = MIN(NUM_CLIPS_FOR_CURRENT, MAX(0, numClips)); }
BuyPresetWeapon weapon( weaponID ); weapon.SetAmmoType( AMMO_CLIPS ); weapon.SetAmmoAmount( numClips ); weapon.SetFillAmmo( (clipModifier == '+') ); weapons.AddToTail( weapon );
remainder = SharedParse( remainder ); } }
//--------------------------------------------------------------------------------------------------------------
/**
* Populates data from a KeyValues structure, for loading */ void BuyPreset::Parse( KeyValues *data ) { m_name[0] = 0; m_weaponList.RemoveAll();
if (!data) return;
//-------------------------------------------------------------------------
// Read name
wcsncpy( m_name, data->GetWString( "PresetName", L""), MaxBuyPresetName ); m_name[ MaxBuyPresetName - 1 ] = 0; PRESET_DEBUG( "Parsing Buy Preset %ls\n", m_name );
int version = data->GetInt( "Version", 0 ); if ( version < 4 || version > 4 ) { PRESET_DEBUG( "Invalid preset version %d\n", version ); return; }
const char *primaryString = data->GetString( "Primary", NULL ); const char *secondaryString = data->GetString( "Secondary", NULL ); const char *equipmentString = data->GetString( "Equipment", NULL );
CUtlVector< BuyPresetWeapon > weapons; ParseWeaponString( primaryString, weapons, true );
WeaponSet ws; if ( weapons.Count() ) ws.m_primaryWeapon = weapons[0];
weapons.RemoveAll(); ParseWeaponString( secondaryString, weapons, false ); if ( weapons.Count() ) ws.m_secondaryWeapon = weapons[0];
// parse equipment
if ( equipmentString ) { const char *remainder = SharedParse( equipmentString ); const char *token;
const int BufLen = 32; char tmpBuf[BufLen]; char itemBuf[BufLen]; int intVal;
while ( remainder ) { token = SharedGetToken(); if ( !token || Q_strlen(token) >= BufLen ) break;
Q_strncpy( tmpBuf, token, BufLen ); tmpBuf[BufLen - 1] = 0; char *tmp = tmpBuf; while ( *tmp ) { if ( *tmp == '/' ) { *tmp = ' '; } ++tmp; } // sscanf is safe, since the size of the string being scanned is at least as small as any individual destination buffer
if ( sscanf( tmpBuf, "%s %d", itemBuf, &intVal ) != 2 ) break;
if ( !strcmp( itemBuf, "vest" ) ) { ws.m_armor = (intVal > 0) ? 100 : 0; ws.m_helmet = false; } else if ( !strcmp( itemBuf, "vesthelm" ) ) { ws.m_armor = (intVal > 0) ? 100 : 0; ws.m_helmet = true; } else if ( !strcmp( itemBuf, "defuser" ) ) { ws.m_defuser = (intVal > 0); } else if ( !strcmp( itemBuf, "nvgs" ) ) { ws.m_nightvision = (intVal > 0); } else if ( !strcmp( itemBuf, "sgren" ) ) { ws.m_smokeGrenade = (intVal > 0); } else if ( !strcmp( itemBuf, "hegren" ) ) { ws.m_HEGrenade = (intVal > 0); } else if ( !strcmp( itemBuf, "flash" ) ) { ws.m_flashbangs = MIN( 2, MAX( 0, intVal ) ); }
remainder = SharedParse( remainder ); }
m_weaponList.AddToTail( ws ); } }
//--------------------------------------------------------------------------------------------------------------
// Build a string of weapons+ammo for KeyValues saving/loading
static const char* ConstructWeaponString( const BuyPresetWeapon& weapon ) { const int WeaponLen = 1024; static char weaponString[WeaponLen]; weaponString[0] = 0; int remainder = WeaponLen; char *tmp = weaponString;
tmp = BufPrintf( tmp, remainder, "%s/%d%c", WeaponIDToAlias( weapon.GetCSWeaponID() ), weapon.GetAmmoAmount(), (weapon.GetFillAmmo()) ? '+' : '=' ); return weaponString; }
//--------------------------------------------------------------------------------------------------------------
/**
* Fills in a KeyValues structure with data, for saving */ void BuyPreset::Save( KeyValues *data ) { //-------------------------------------------------------------------------
// Save name and version
KeyValues *presetKey = data->CreateNewKey(); presetKey->SetWString( "PresetName", m_name );
/**
* Version History * --------------- * * PRE-RELEASE * 1. 2/2004 * First-pass implementation. Allowed for multiple weapons per fallback. * Individual items could be marked optional. Cash reserve could be specified. * 2. 3/2004 * Second-pass implementation. Removed multiple weapons per fallback. The * pistol could be marked optional. A preset could be marked as 'use for * Autobuy'. * * CZ RELEASE * 3. 4/22/2004 * The first released version. Removed optional/required status. Also * removed the cash reserve and autobuy status. Corresponds to streamlined * editing interface mocked up by Greg Coomer. * * CS:S RELEASE * 4. 3/10/2004 * Removed fallbacks to correspond to new UI. */ presetKey->SetInt( "Version", 4 ); if ( m_weaponList.Count() > 0 ) { //-------------------------------------------------------------------------
// Save a fallback WeaponSet
const WeaponSet& ws = m_weaponList[0];
presetKey->SetString( "Primary", ConstructWeaponString( ws.m_primaryWeapon ) ); presetKey->SetString( "Secondary", ConstructWeaponString( ws.m_secondaryWeapon ) );
presetKey->SetString( "Equipment", SharedVarArgs("vest%s/%d flash/%d sgren/%d hegren/%d defuser/%d nvgs/%d", (ws.m_helmet)?"helm":"", ws.m_armor, ws.m_flashbangs, ws.m_smokeGrenade, ws.m_HEGrenade, ws.m_defuser, ws.m_nightvision ) ); } }
//--------------------------------------------------------------------------------------------------------------
/**
* Calculates the full cost of the preset, which is exactly the full cost of the first fallback WeaponSet */ int BuyPreset::FullCost() const { if ( m_weaponList.Count() == 0 ) return 0;
return m_weaponList[0].FullCost(); }
//--------------------------------------------------------------------------------------------------------------
/**
* Returns the specified fallback WeaponSet, or NULL if it doesn't exist */ const WeaponSet * BuyPreset::GetSet( int index ) const { if ( index < 0 || index >= m_weaponList.Count() ) return NULL;
return &(m_weaponList[index]); }
//--------------------------------------------------------------------------------------------------------------
/**
* Deletes a fallback */ void BuyPreset::DeleteSet( int index ) { if ( index < 0 || index >= m_weaponList.Count() ) return;
m_weaponList.Remove( index ); }
//--------------------------------------------------------------------------------------------------------------
/**
* Switches the order of two fallbacks */ void BuyPreset::SwapSet( int firstIndex, int secondIndex ) { if ( firstIndex < 0 || firstIndex >= m_weaponList.Count() ) return;
if ( secondIndex < 0 || secondIndex >= m_weaponList.Count() ) return;
WeaponSet tmpSet = m_weaponList[firstIndex]; m_weaponList[firstIndex] = m_weaponList[secondIndex]; m_weaponList[secondIndex] = tmpSet; }
//--------------------------------------------------------------------------------------------------------------
/**
* Replaces a fallback with the supplied WeaponSet */ void BuyPreset::ReplaceSet( int index, const WeaponSet& weaponSet ) { if ( index < 0 || index > m_weaponList.Count() ) return;
if ( index == m_weaponList.Count() ) { m_weaponList.AddToTail( weaponSet ); } else { m_weaponList[index] = weaponSet; } }
//--------------------------------------------------------------------------------------------------------------
|