ns/main/source/cl_dll/ammo.cpp
XP-Cagey b918c731aa Bugfixes for mantis #1008, #1009
Rewrote WeaponsResource code so that uninitialized slots are no longer returned as valid weapons
Removed upp_* from command constants and console commands
Removed commented out entry from hl_baseentity.cpp
Shift in map data position is now performed by the network layer instead of at the time of creation
Deleted obsolete Util.vcproj
Replaced calls to fmax with calls to max in AvHEntities.cpp (Win32 compiler wasn't finding fmax command without explicit include)
Began implementation of client-to-server tunnel for Nexus


git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@94 67975925-1194-0748-b3d5-c16f83f1a3a1
2005-05-05 15:20:23 +00:00

1350 lines
32 KiB
C++

/***
*
* Copyright (c) 1999, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
//
// Ammo.cpp
//
// implementation of CHudAmmo class
//
#include "hud.h"
#include "cl_util.h"
#include <string.h>
#include <stdio.h>
#include "ammohistory.h"
#include "vgui_TeamFortressViewport.h"
#include "mod/AvHSharedUtil.h"
#include "mod/AvHScrollHandler.h"
#include "mod/AvHNetworkMessages.h"
WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise
// this points to the active weapon menu item
WEAPON *gpLastSel; // Last weapon menu selection
bool HUD_GetWeaponEnabled(int inID);
client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount);
WeaponsResource gWR;
int g_weaponselect = 0;
//Equivalent to DECLARE_COMMAND(lastinv,LastInv) except we use gWR instead of gHud
void __CmdFunc_LastInv(void)
{ gWR.UserCmd_LastInv(); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WeaponsResource::WeaponsResource(void) : lastWeapon(NULL), iOldWeaponBits(0) {}
WeaponsResource::~WeaponsResource(void) {}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::Init( void )
{
memset( rgWeapons, 0, sizeof(WEAPON)*MAX_WEAPONS );
Reset();
HOOK_COMMAND("lastinv",LastInv);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::Reset( void )
{
lastWeapon = NULL;
iOldWeaponBits = 0;
memset( rgSlots, 0, sizeof(WEAPON*)*MAX_WEAPON_SLOTS*MAX_WEAPON_POSITIONS );
memset( riAmmo, 0, sizeof(int)*MAX_AMMO_TYPES );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource :: LoadAllWeaponSprites( void )
{
for (int i = 0; i < MAX_WEAPONS; i++)
{
if ( rgWeapons[i].iId )
LoadWeaponSprites( &rgWeapons[i] );
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline void LoadWeaponSprite( client_sprite_t* ptr, HSPRITE& sprite, wrect_t& bounds )
{
if( ptr )
{
string name( "sprites/" );
name.append( ptr->szSprite );
name.append( ".spr" );
sprite = Safe_SPR_Load(name.c_str());
bounds = ptr->rc;
}
else
{
sprite = NULL;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon )
{
int i, iRes;
if (ScreenWidth() < 640)
iRes = 320;
else
iRes = 640;
char sz[128];
if ( !pWeapon )
return;
memset( &pWeapon->rcActive, 0, sizeof(wrect_t) );
memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) );
memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) );
memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) );
pWeapon->hInactive = 0;
pWeapon->hActive = 0;
pWeapon->hAmmo = 0;
pWeapon->hAmmo2 = 0;
sprintf(sz, "sprites/%s.txt", pWeapon->szName);
client_sprite_t *pList = SPR_GetList(sz, &i);
if (!pList)
{
ASSERT(pList);
return;
}
LoadWeaponSprite( GetSpriteList( pList, "crosshair", iRes, i ), pWeapon->hCrosshair, pWeapon->rcCrosshair );
LoadWeaponSprite( GetSpriteList( pList, "autoaim", iRes, i ), pWeapon->hAutoaim, pWeapon->rcAutoaim );
LoadWeaponSprite( GetSpriteList( pList, "zoom", iRes, i ), pWeapon->hZoomedCrosshair, pWeapon->rcZoomedCrosshair );
LoadWeaponSprite( GetSpriteList( pList, "zoom_autoaim", iRes, i ), pWeapon->hZoomedAutoaim, pWeapon->rcZoomedAutoaim );
LoadWeaponSprite( GetSpriteList( pList, "weapon", iRes, i ), pWeapon->hInactive, pWeapon->rcInactive );
LoadWeaponSprite( GetSpriteList( pList, "weapon_s", iRes, i ), pWeapon->hActive, pWeapon->rcActive );
LoadWeaponSprite( GetSpriteList( pList, "ammo", iRes, i ), pWeapon->hAmmo, pWeapon->rcAmmo );
LoadWeaponSprite( GetSpriteList( pList, "ammo2", iRes, i ), pWeapon->hAmmo2, pWeapon->rcAmmo2 );
if( pWeapon->hZoomedCrosshair == NULL ) //default to non-zoomed crosshair
{
pWeapon->hZoomedCrosshair = pWeapon->hCrosshair;
pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair;
}
if( pWeapon->hAutoaim == NULL ) //default to non-autoaim crosshair
{
pWeapon->hAutoaim = pWeapon->hCrosshair;
pWeapon->rcAutoaim = pWeapon->rcCrosshair;
}
if( pWeapon->hZoomedAutoaim == NULL ) //default to non-autoaim zoomed crosshair
{
pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair;
pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair;
}
if( pWeapon->hActive || pWeapon->hInactive || pWeapon->hAmmo || pWeapon->hAmmo2 )
{ gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WEAPON* WeaponsResource::GetWeapon( int iId ) { return rgWeapons[iId].iId ? &rgWeapons[iId] : NULL; }
WEAPON* WeaponsResource::GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WEAPON* WeaponsResource::GetFirstPos( int iSlot )
{
WEAPON *returnVal = NULL;
ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 );
for( int counter = 0; counter < MAX_WEAPON_POSITIONS; ++counter )
{
if( this->IsSelectable(rgSlots[iSlot][counter]) )
{
returnVal = rgSlots[iSlot][counter];
break;
}
}
return returnVal;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WEAPON* WeaponsResource::GetNextActivePos( int iSlot, int iSlotPos )
{
WEAPON* returnVal = NULL;
ASSERT( iSlot < MAX_WEAPON_SLOTS && iSlot >= 0 );
ASSERT( iSlotPos >= 0 );
for( int counter = iSlotPos+1; counter < MAX_WEAPON_POSITIONS; ++counter )
{
if( this->IsSelectable(rgSlots[iSlot][counter]) )
{
returnVal = rgSlots[iSlot][counter];
break;
}
}
return returnVal;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool WeaponsResource::IsEnabled(WEAPON* p)
{
if( p == NULL ) { return false; }
return HUD_GetWeaponEnabled(p->iId) && this->HasAmmo(p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool WeaponsResource::IsSelectable(WEAPON* p)
{
if( p == NULL ) { return false; }
return HUD_GetWeaponEnabled(p->iId);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool WeaponsResource::HasAmmo( WEAPON* p )
{
if( p == NULL) { return false; }
//note : if max ammo capacity is -1, this has always returned true in spite of not
// having actual ammo -- KGP
return (p->iAmmoType == -1) || (p->iMax1 == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType)
|| CountAmmo(p->iAmmo2Type) || (p->iFlags & WEAPON_FLAGS_SELECTIONEMPTY );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int WeaponsResource::CountAmmo( int iId )
{
ASSERT( iId < MAX_AMMO_TYPES );
if( iId < 0 ) return 0;
return riAmmo[iId];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int WeaponsResource::GetAmmo( int iId )
{
ASSERT( iId < MAX_AMMO_TYPES && iId > -1 );
return riAmmo[iId];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::SetAmmo( int iId, int iCount )
{
ASSERT( iId < MAX_AMMO_TYPES && iId > -1 );
riAmmo[iId] = iCount;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HSPRITE* WeaponsResource::GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect )
{
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
if ( rgWeapons[i].iAmmoType == iAmmoId )
{
rect = rgWeapons[i].rcAmmo;
return &rgWeapons[i].hAmmo;
}
else if ( rgWeapons[i].iAmmo2Type == iAmmoId )
{
rect = rgWeapons[i].rcAmmo2;
return &rgWeapons[i].hAmmo2;
}
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::AddWeapon( WEAPON *wp )
{
rgWeapons[ wp->iId ] = *wp;
LoadWeaponSprites( &rgWeapons[ wp->iId ] );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::PickupWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::DropWeapon( WEAPON *wp )
{
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL;
if(lastWeapon == wp) //dropped last weapon, remove it from the list
{ lastWeapon = NULL; }
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::DropAllWeapons( void )
{
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
if ( rgWeapons[i].iId )
DropWeapon( &rgWeapons[i] );
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::UserCmd_LastInv(void)
{
if(this->IsSelectable(this->lastWeapon))
{
this->SetCurrentWeapon(lastWeapon);
const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON);
gHUD.PlayHUDSound(theSound, kHUDSoundVolume);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::SetValidWeapon(void)
{
WEAPON* p = this->GetFirstPos(0); //alien attack 1 or primary marine weapon
if(gHUD.GetIsAlien())
{
this->SetCurrentWeapon(p);
}
else
{
if(this->IsSelectable(p) && this->HasAmmo(p))
{
this->SetCurrentWeapon(p);
}
else
{
p = this->GetFirstPos(1); //pistol slot
if(this->IsSelectable(p) && this->HasAmmo(p))
{
this->SetCurrentWeapon(p);
}
else
{
p = this->GetFirstPos(2); //knife slot
this->SetCurrentWeapon(p);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource::SetCurrentWeapon(WEAPON* newWeapon)
{
WEAPON* currentWeapon = this->GetWeapon(gHUD.GetCurrentWeaponID());
// puzl: 497 - Because weapon state can get out of sync, we should allow this even if the weapons are the same
// && newWeapon != currentWeapon
if( newWeapon != NULL )
{
if( newWeapon != currentWeapon )
{ lastWeapon = currentWeapon; }
ServerCmd(newWeapon->szName);
g_weaponselect = newWeapon->iId;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection )
{
if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) )
{ // menu is overriding slot use commands
gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers
return;
}
if ( iSlot >= MAX_WEAPON_SLOTS )
return;
if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) )
return;
if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) //require suit
return;
if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) //require something besides suit
return;
WEAPON *p = NULL;
bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0;
if ((gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot))
{
p = GetFirstPos(iSlot);
const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_ON);
gHUD.PlayHUDSound(theSound, kHUDSoundVolume);
if (this->IsSelectable(p) && fastSwitch) //check to see if we can use fastSwitch
{
WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos );
if (!this->IsSelectable(p2)) //only one target in the bucket
{
this->SetCurrentWeapon(p);
return;
}
}
}
else
{
const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_MOVE_SELECT);
gHUD.PlayHUDSound(theSound, kHUDSoundVolume);
if ( gpActiveSel )
p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos );
if ( !p )
p = GetFirstPos( iSlot );
}
if (!this->IsSelectable(p)) // no valid selection found
{
// if fastSwitch is on, ignore, else turn on the menu
if ( !fastSwitch ) {
gpActiveSel = (WEAPON *)1;
}
else {
gpActiveSel = NULL;
}
}
else
{
gpActiveSel = p;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height
HSPRITE ghsprBuckets; // Sprite for top row of weapons menu
DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip
DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type
DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count
DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record
DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record
DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily
DECLARE_MESSAGE(m_Ammo, ItemPickup);
DECLARE_COMMAND(m_Ammo, Slot1);
DECLARE_COMMAND(m_Ammo, Slot2);
DECLARE_COMMAND(m_Ammo, Slot3);
DECLARE_COMMAND(m_Ammo, Slot4);
DECLARE_COMMAND(m_Ammo, Slot5);
DECLARE_COMMAND(m_Ammo, Slot6);
DECLARE_COMMAND(m_Ammo, Slot7);
DECLARE_COMMAND(m_Ammo, Slot8);
DECLARE_COMMAND(m_Ammo, Slot9);
DECLARE_COMMAND(m_Ammo, Slot10);
DECLARE_COMMAND(m_Ammo, Close);
DECLARE_COMMAND(m_Ammo, NextWeapon);
DECLARE_COMMAND(m_Ammo, PrevWeapon);
// width of ammo fonts
#define AMMO_SMALL_WIDTH 10
#define AMMO_LARGE_WIDTH 20
#define HISTORY_DRAW_TIME "5"
int CHudAmmo::Init(void)
{
gHUD.AddHudElem(this);
HOOK_MESSAGE(CurWeapon);
HOOK_MESSAGE(WeaponList);
HOOK_MESSAGE(AmmoPickup);
HOOK_MESSAGE(WeapPickup);
HOOK_MESSAGE(ItemPickup);
HOOK_MESSAGE(HideWeapon);
HOOK_MESSAGE(AmmoX);
HOOK_COMMAND("slot1", Slot1);
HOOK_COMMAND("slot2", Slot2);
HOOK_COMMAND("slot3", Slot3);
HOOK_COMMAND("slot4", Slot4);
HOOK_COMMAND("slot5", Slot5);
HOOK_COMMAND("slot6", Slot6);
HOOK_COMMAND("slot7", Slot7);
HOOK_COMMAND("slot8", Slot8);
HOOK_COMMAND("slot9", Slot9);
HOOK_COMMAND("slot10", Slot10);
HOOK_COMMAND("cancelselect", Close);
HOOK_COMMAND("invnext", NextWeapon);
HOOK_COMMAND("invprev", PrevWeapon);
Reset();
CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 );
CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress
m_iFlags |= HUD_ACTIVE; //!!!
gWR.Init();
gHR.Init();
return 1;
};
void CHudAmmo::Reset(void)
{
m_fFade = 0;
m_iFlags |= HUD_ACTIVE; //!!!
gpActiveSel = NULL;
gHUD.m_iHideHUDDisplay = 0;
gWR.Reset();
gHR.Reset();
// VidInit();
}
int CHudAmmo::VidInit(void)
{
// Load sprites for buckets (top row of weapon menu)
m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" );
m_HUD_selection = gHUD.GetSpriteIndex( "selection" );
ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0);
giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left;
giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top;
gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top);
// If we've already loaded weapons, let's get new sprites
gWR.LoadAllWeaponSprites();
if (ScreenWidth() >= 640)
{
giABWidth = 20;
giABHeight = 4;
}
else
{
giABWidth = 10;
giABHeight = 2;
}
return 1;
}
//
// Think:
// Used for selection of weapon menu item.
//
void CHudAmmo::Think(void)
{
if ( gHUD.m_fPlayerDead )
return;
if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits )
{
gWR.iOldWeaponBits = gHUD.m_iWeaponBits;
bool droppedCurrent = false;
for (int i = MAX_WEAPONS-1; i > 0; i-- )
{
WEAPON *p = gWR.GetWeapon(i);
if ( p )
{
if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) )
gWR.PickupWeapon( p );
else
gWR.DropWeapon( p );
}
}
}
if(gHUD.GetIsAlien()) //check for hive death causing loss of current weapon
{
WEAPON* currentWeapon = gWR.GetWeapon(gHUD.GetCurrentWeaponID());
if(!gWR.IsSelectable(currentWeapon)) //current weapon isn't valid
{
gWR.SetValidWeapon(); //get best option
}
}
if (!gpActiveSel)
return;
// has the player selected one?
if (gHUD.m_iKeyBits & IN_ATTACK)
{
if (gpActiveSel != (WEAPON *)1)
{
gWR.SetCurrentWeapon(gpActiveSel);
}
gpLastSel = gpActiveSel;
gpActiveSel = NULL;
gHUD.m_iKeyBits &= ~IN_ATTACK;
const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_SELECT);
gHUD.PlayHUDSound(theSound, kHUDSoundVolume);
}
}
//------------------------------------------------------------------------
// Message Handlers
//------------------------------------------------------------------------
//
// AmmoX -- Update the count of a known type of ammo
//
int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf)
{
int iIndex, iCount;
NetMsg_AmmoX( pbuf, iSize, iIndex, iCount );
gWR.SetAmmo( iIndex, abs(iCount) );
return 1;
}
int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf )
{
int iIndex, iCount;
NetMsg_AmmoPickup( pbuf, iSize, iIndex, iCount );
// Add ammo to the history
gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) );
return 1;
}
int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf )
{
int iIndex;
NetMsg_WeapPickup( pbuf, iSize, iIndex );
// Add the weapon to the history
gHR.AddToHistory( HISTSLOT_WEAP, iIndex );
return 1;
}
int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf )
{
string szName;
NetMsg_ItemPickup( pbuf, iSize, szName );
// Add the weapon to the history
gHR.AddToHistory( HISTSLOT_ITEM, szName.c_str() );
return 1;
}
int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf )
{
NetMsg_HideWeapon( pbuf, iSize, gHUD.m_iHideHUDDisplay );
if (gEngfuncs.IsSpectateOnly())
return 1;
if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) )
{
static wrect_t nullrc;
gpActiveSel = NULL;
gHUD.SetCurrentCrosshair( 0, nullrc, 0, 0, 0 );
}
else
{
if ( m_pWeapon )
gHUD.SetCurrentCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 );
}
return 1;
}
//
// CurWeapon: Update hud state with the current weapon and clip count. Ammo
// counts are updated with AmmoX. Server assures that the Weapon ammo type
// numbers match a real ammo type.
//
int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf )
{
static wrect_t nullrc;
int iState, iId, iClip;
NetMsg_CurWeapon( pbuf, iSize, iState, iId, iClip );
if ( iId < 1 ) //signal kills crosshairs if this condition is met...
{
gHUD.SetCurrentCrosshair(0, nullrc, 0, 0, 0);
return 0;
}
if ( g_iUser1 != OBS_IN_EYE )
{
if ( iId == -1 && iClip == -1 ) //this conditional is never true due to iId < 1 check above!
{
gHUD.m_fPlayerDead = TRUE;
gpActiveSel = NULL;
return 1;
}
gHUD.m_fPlayerDead = FALSE;
}
WEAPON *pWeapon = gWR.GetWeapon( iId );
if( pWeapon == NULL ) //don't have the weapon described in our resource list
{ return 0; }
bool bOnTarget = (iState & WEAPON_ON_TARGET) != 0; //used to track autoaim state
bool bIsCurrent = (iState & WEAPON_IS_CURRENT) != 0;
pWeapon->iEnabled = (iState & WEAPON_IS_ENABLED) != 0 ? TRUE : FALSE;
pWeapon->iClip = abs(iClip);
if( !bIsCurrent )
{ return 1; }
m_pWeapon = pWeapon;
if ( !(gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
{
if ( gHUD.m_iFOV >= 90 )
{ // normal crosshairs
if (bOnTarget && m_pWeapon->hAutoaim)
gHUD.SetCurrentCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255);
else
gHUD.SetCurrentCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255);
}
else
{ // zoomed crosshairs
if (bOnTarget && m_pWeapon->hZoomedAutoaim)
gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255);
else
gHUD.SetCurrentCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255);
}
}
m_fFade = 200.0f; //!!!
m_iFlags |= HUD_ACTIVE;
return 1;
}
//
// WeaponList -- Tells the hud about a new weapon type.
//
int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf )
{
WeaponList weapon_data;
NetMsg_WeaponList( pbuf, iSize, weapon_data );
WEAPON Weapon;
memset( &Weapon, 0, sizeof(WEAPON) );
strcpy( Weapon.szName, weapon_data.weapon_name.c_str() );
Weapon.iAmmoType = weapon_data.ammo1_type;
Weapon.iMax1 = weapon_data.ammo1_max_amnt == 255 ? -1 : weapon_data.ammo1_max_amnt;
Weapon.iAmmo2Type = weapon_data.ammo2_type;
Weapon.iMax2 = weapon_data.ammo2_max_amnt == 255 ? -1 : weapon_data.ammo2_max_amnt;
Weapon.iSlot = weapon_data.bucket;
Weapon.iSlotPos = weapon_data.bucket_pos;
Weapon.iId = weapon_data.bit_index;
Weapon.iFlags = weapon_data.flags;
Weapon.iClip = 0;
// puzl: 497 - default value for enable state
Weapon.iEnabled = 0;
gWR.AddWeapon( &Weapon );
return 1;
}
//------------------------------------------------------------------------
// Command Handlers
//------------------------------------------------------------------------
// Slot button pressed
void CHudAmmo::SlotInput( int iSlot )
{
// Let the Viewport use it first, for menus
if ( gViewPort && gViewPort->SlotInput( iSlot ) )
return;
gWR.SelectSlot( iSlot, FALSE, 1 );
}
void CHudAmmo::UserCmd_Slot1(void)
{
SlotInput( 0 );
}
void CHudAmmo::UserCmd_Slot2(void)
{
SlotInput( 1 );
}
void CHudAmmo::UserCmd_Slot3(void)
{
SlotInput( 2 );
}
void CHudAmmo::UserCmd_Slot4(void)
{
SlotInput( 3 );
}
void CHudAmmo::UserCmd_Slot5(void)
{
SlotInput( 4 );
}
void CHudAmmo::UserCmd_Slot6(void)
{
SlotInput( 5 );
}
void CHudAmmo::UserCmd_Slot7(void)
{
SlotInput( 6 );
}
void CHudAmmo::UserCmd_Slot8(void)
{
SlotInput( 7 );
}
void CHudAmmo::UserCmd_Slot9(void)
{
SlotInput( 8 );
}
void CHudAmmo::UserCmd_Slot10(void)
{
SlotInput( 9 );
}
void CHudAmmo::UserCmd_Close(void)
{
if (gpActiveSel)
{
gpLastSel = gpActiveSel;
gpActiveSel = NULL;
const char* theSound = AvHSHUGetCommonSoundName(gHUD.GetIsAlien(), WEAPON_SOUND_HUD_OFF);
gHUD.PlayHUDSound(theSound, kHUDSoundVolume);
}
}
// Selects the next item in the weapon menu
void CHudAmmo::UserCmd_NextWeapon(void)
{
if(gHUD.GetInTopDownMode())
{
AvHScrollHandler::ScrollHeightUp();
}
if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) )
return;
if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 )
gpActiveSel = m_pWeapon;
int pos = 0;
int slot = 0;
if ( gpActiveSel )
{
pos = gpActiveSel->iSlotPos + 1;
slot = gpActiveSel->iSlot;
}
for ( int loop = 0; loop <= 1; loop++ )
{
for ( ; slot < MAX_WEAPON_SLOTS; slot++ )
{
for ( ; pos < MAX_WEAPON_POSITIONS; pos++ )
{
WEAPON *wsp = gWR.GetWeaponSlot( slot, pos );
if (gWR.IsSelectable(wsp))
{
gpActiveSel = wsp;
return;
}
}
pos = 0;
}
slot = 0; // start looking from the first slot again
}
gpActiveSel = NULL;
}
// Selects the previous item in the menu
void CHudAmmo::UserCmd_PrevWeapon(void)
{
if(gHUD.GetInTopDownMode())
{
AvHScrollHandler::ScrollHeightDown();
}
if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) )
return;
if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 )
gpActiveSel = m_pWeapon;
int pos = MAX_WEAPON_POSITIONS-1;
int slot = MAX_WEAPON_SLOTS-1;
if ( gpActiveSel )
{
pos = gpActiveSel->iSlotPos - 1;
slot = gpActiveSel->iSlot;
}
for ( int loop = 0; loop <= 1; loop++ )
{
for ( ; slot >= 0; slot-- )
{
for ( ; pos >= 0; pos-- )
{
WEAPON *wsp = gWR.GetWeaponSlot( slot, pos );
if (gWR.IsSelectable(wsp))
{
gpActiveSel = wsp;
return;
}
}
pos = MAX_WEAPON_POSITIONS-1;
}
slot = MAX_WEAPON_SLOTS-1;
}
gpActiveSel = NULL;
}
void CHudAmmo::SetCurrentClip(int inClip)
{
if(this->m_pWeapon)
{
this->m_pWeapon->iClip = inClip;
}
}
//-------------------------------------------------------------------------
// Drawing code
//-------------------------------------------------------------------------
int CHudAmmo::Draw(float flTime)
{
int a, x, y, r, g, b;
int AmmoWidth;
if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ))
return 1;
if (/*!gHUD.GetIsAlive() ||*/ (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) )
return 1;
// Draw Weapon Menu
DrawWList(flTime);
// Draw ammo pickup history
gHR.DrawAmmoHistory( flTime );
if (!(m_iFlags & HUD_ACTIVE))
return 0;
if (!m_pWeapon)
return 0;
WEAPON *pw = m_pWeapon; // shorthand
// SPR_Draw Ammo
if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0))
return 0;
int iFlags = DHN_DRAWZERO; // draw 0 values
AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
a = (int) max( MIN_ALPHA, m_fFade );
if (m_fFade > 0)
m_fFade -= (gHUD.m_flTimeDelta * 20);
gHUD.GetPrimaryHudColor(r, g, b);
ScaleColors(r, g, b, a );
int theViewport[4];
gHUD.GetViewport(theViewport);
// Does this weapon have a clip?
y = theViewport[1] + theViewport[3] - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2;
// Does weapon have any ammo at all?
if (m_pWeapon->iAmmoType > 0)
{
int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left;
if (pw->iClip >= 0)
{
// room for the number and the '|' and the current ammo
x = theViewport[0] + theViewport[2] - (8 * AmmoWidth) - iIconWidth;
x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b);
wrect_t rc;
rc.top = 0;
rc.left = 0;
rc.right = AmmoWidth;
rc.bottom = 100;
int iBarWidth = AmmoWidth/10;
x += AmmoWidth/2;
gHUD.GetPrimaryHudColor(r, g, b);
// draw the | bar
FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a);
x += iBarWidth + AmmoWidth/2;;
// GL Seems to need this
ScaleColors(r, g, b, a );
x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b);
}
else
{
// SPR_Draw a bullets only line
x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth;
x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b);
}
// Draw the ammo Icon
int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8;
SPR_Set(m_pWeapon->hAmmo, r, g, b);
SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo);
}
// Does weapon have seconday ammo?
if (pw->iAmmo2Type > 0)
{
int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left;
// Do we have secondary ammo?
if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0))
{
y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4;
x = theViewport[0] + theViewport[2] - 4 * AmmoWidth - iIconWidth;
x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b);
// Draw the ammo Icon
SPR_Set(m_pWeapon->hAmmo2, r, g, b);
int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8;
SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2);
}
}
return 1;
}
//
// Draws the ammo bar on the hud
//
int DrawBar(int x, int y, int width, int height, float f)
{
int r, g, b;
if (f < 0)
f = 0;
if (f > 1)
f = 1;
if (f)
{
int w = f * width;
// Always show at least one pixel if we have ammo.
if (w <= 0)
w = 1;
UnpackRGB(r, g, b, RGB_GREENISH);
FillRGBA(x, y, w, height, r, g, b, 255);
x += w;
width -= w;
}
gHUD.GetPrimaryHudColor(r, g, b);
FillRGBA(x, y, width, height, r, g, b, 128);
return (x + width);
}
void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height)
{
if ( !p )
return;
if (p->iAmmoType != -1)
{
if (!gWR.CountAmmo(p->iAmmoType))
return;
float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1;
x = DrawBar(x, y, width, height, f);
// Do we have secondary ammo too?
if (p->iAmmo2Type != -1)
{
f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2;
x += 5; //!!!
DrawBar(x, y, width, height, f);
}
}
}
//
// Draw Weapon Menu
//
int CHudAmmo::DrawWList(float flTime)
{
int r,g,b,x,y,a,i;
if ( !gpActiveSel )
{
gHUD.SetSelectingWeaponID(-1);
return 0;
}
int iActiveSlot;
if ( gpActiveSel == (WEAPON *)1 )
iActiveSlot = -1; // current slot has no weapons
else
iActiveSlot = gpActiveSel->iSlot;
x = 10; //!!!
y = 10; //!!!
// Ensure that there are available choices in the active slot
if ( iActiveSlot > 0 )
{
if ( !gWR.GetFirstPos( iActiveSlot ) )
{
gpActiveSel = (WEAPON *)1;
iActiveSlot = -1;
}
}
// Draw top line
for ( i = 0; i < MAX_WEAPON_SLOTS; i++ )
{
int iWidth;
gHUD.GetPrimaryHudColor(r, g, b);
if ( iActiveSlot == i )
a = 255;
else
a = 192;
ScaleColors(r, g, b, 255);
SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b );
// make active slot wide enough to accomodate gun pictures
if ( i == iActiveSlot )
{
WEAPON *p = gWR.GetFirstPos(iActiveSlot);
if ( p )
iWidth = p->rcActive.right - p->rcActive.left;
else
iWidth = giBucketWidth;
}
else
iWidth = giBucketWidth;
SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i));
x += iWidth + 5;
}
a = 128; //!!!
x = 10;
// Draw all of the buckets
for (i = 0; i < MAX_WEAPON_SLOTS; i++)
{
y = giBucketHeight + 10;
// If this is the active slot, draw the bigger pictures,
// otherwise just draw boxes
if ( i == iActiveSlot )
{
WEAPON *p = gWR.GetFirstPos( i );
int iWidth = giBucketWidth;
if ( p )
iWidth = p->rcActive.right - p->rcActive.left;
for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ )
{
p = gWR.GetWeaponSlot( i, iPos );
if ( !p || !p->iId )
continue;
// Preserve red/yellow depending on whether it has ammo or not
if(!gWR.IsEnabled(p))
{
UnpackRGB(r,g,b, RGB_REDISH);
ScaleColors(r, g, b, 128);
}
else
{
gHUD.GetPrimaryHudColor(r, g, b);
ScaleColors(r, g, b, 192);
}
if ( gpActiveSel == p )
{
SPR_Set(p->hActive, r, g, b );
SPR_DrawAdditive(0, x, y, &p->rcActive);
SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b );
SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection));
// Lookup iID for helptext
gHUD.SetSelectingWeaponID(p->iId, r, g, b);
}
else
{
// Draw Weapon if Red if no ammo
//if (gWR.IsSelectable(p))
// ScaleColors(r, g, b, 192);
//else
//{
// UnpackRGB(r,g,b, RGB_REDISH);
// ScaleColors(r, g, b, 128);
//}
SPR_Set( p->hInactive, r, g, b );
SPR_DrawAdditive( 0, x, y, &p->rcInactive );
}
// Draw Ammo Bar
DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight);
y += p->rcActive.bottom - p->rcActive.top + 5;
}
x += iWidth + 5;
}
else
{
// Draw Row of weapons.
gHUD.GetPrimaryHudColor(r, g, b);
for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ )
{
WEAPON *p = gWR.GetWeaponSlot( i, iPos );
if ( !p || !p->iId )
continue;
if ( gWR.IsEnabled(p) )
{
gHUD.GetPrimaryHudColor(r, g, b);
a = 128;
}
else
{
UnpackRGB(r,g,b, RGB_REDISH);
a = 96;
}
FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a );
y += giBucketHeight + 5;
}
x += giBucketWidth + 5;
}
}
return 1;
}
/* =================================
GetSpriteList
Finds and returns the matching
sprite name 'psz' and resolution 'iRes'
in the given sprite list 'pList'
iCount is the number of items in the pList
================================= */
client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount)
{
if (!pList)
return NULL;
int i = iCount;
client_sprite_t *p = pList;
while(i--)
{
if ((!strcmp(psz, p->szName)) && (p->iRes == iRes))
return p;
p++;
}
return NULL;
}