ns/releases/3.2.0/source/mod/AvHHud.cpp
puzl 5dcc163bd5 made a copy
git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@379 67975925-1194-0748-b3d5-c16f83f1a3a1
2006-04-02 10:49:08 +00:00

7017 lines
189 KiB
C++

//======== (C) Copyright 2001 Charles G. Cleveland All rights reserved. =========
//
// The copyright to the contents herein is the property of Charles G. Cleveland.
// The contents may be used and/or copied only with the written permission of
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: Main NS NUD, also interface to client network messages
//
// $Workfile: AvHHud.cpp $
// $Date: 2002/10/28 20:35:32 $
//
//-------------------------------------------------------------------------------
// $Log: AvHHud.cpp,v $
// Revision 1.70 2002/10/28 20:35:32 Flayra
// - Fix for gamma reset with VAC
// - Info location fix after changelevel
//
// Revision 1.69 2002/10/25 21:49:10 Flayra
// - Updated skin to sit in pev->skin
// - Reset components every tick to fix problem with disappearing team resource label
//
// Revision 1.68 2002/10/24 21:29:49 Flayra
// - Moved help client-side
// - Fixed particle/changelevel crash
// - Reworked marine upgrade drawing
// - Added lots of utility functions for help system (mirrors functions on server)
// - Removed gamma message unless it failed or if maxplayers is 1
// - Fixed alien hive sight crash
// - Show players under reticle while in ready room and spectating
// - Removed ugly/too-prevalent user3 icons
//
// Revision 1.67 2002/10/18 22:19:49 Flayra
// - Added alien easter egg sayings
//
// Revision 1.66 2002/10/16 20:53:41 Flayra
// - Draw scan model specially so it looks right
//
// Revision 1.65 2002/10/16 00:58:02 Flayra
// - Removed hotgroups
// - Added "need order" alert
//
// Revision 1.64 2002/10/03 20:24:39 Flayra
// - Changes for "more resources required"
//
// Revision 1.63 2002/10/03 18:54:30 Flayra
// - Allow right-click to cancel building placement
// - Fixed help icons
// - Added a couple utility functions
// - Reworked order notification
// - Reworked blip network messages to avoid hard-coded limit
// - Sent max resources down with current resources
// - Countdown sound no longer prevents other hud sounds
// - Alien trigger sounds
// - New order sounds
// - No longer disable nodes out of our cost range
//
// Revision 1.62 2002/09/25 20:47:19 Flayra
// - Don't draw elements on HUD when dead
// - UI refactoring
// - Split reticle help into help text and reticle text
// - Removed use order
// - Added separate select sound for alien
// - Multiple move sounds
// - Only draw entity build/health status when under reticle (no more scanning around you)
// - Added 3 new sayings
//
// Revision 1.61 2002/09/23 22:18:25 Flayra
// - Added alien build circles
// - Game status changes so particles aren't sent every time
// - Demo playback changes (save restore basic data that HUD already has)
// - New alert sounds
// - Skin support
//
// Revision 1.60 2002/09/09 19:55:24 Flayra
// - Added hive info indicator
// - Fixed bug where reticle tooltip help text wasn't being set until a weapon was selected
// - Fixed release mode bug where tooltips weren't expiring
// - Fixed bug where marine upgrades blinked
// - "No commander" indicator now blinks
//
// Revision 1.59 2002/08/31 18:01:01 Flayra
// - Work at VALVe
//
// Revision 1.58 2002/08/16 02:37:49 Flayra
// - HUD sounds no longer cut each other off (they won't play instead of cutting off another sound)
// - Tooltip sounds
// - Selection issues
// - Draw rings around buildings that need to be built
// - Removed old overwatch code
//
// Revision 1.57 2002/08/09 01:02:40 Flayra
// - Added hooks for demo playback, removed prediction selection
//
// Revision 1.56 2002/08/02 21:59:12 Flayra
// - Added reticle help, new tooltip system and much nicer order drawing! Refactored view model drawing a bit, hoping to make texture blending work for it.
//
// Revision 1.55 2002/07/26 23:05:01 Flayra
// - Generate numerical feedback for damage events
// - Refactoring for more info when looking at something (instead of bad-looking player names only)
//
// Revision 1.54 2002/07/24 18:45:41 Flayra
// - Linux and scripting changes
//
// Revision 1.53 2002/07/23 17:07:36 Flayra
// - Added visually-smooth energy level, added versatile location code, new hive sight info, refactored to remove extra sprites (128 HUD sprites bug), commander tech help fixes
//
// Revision 1.52 2002/07/10 14:41:55 Flayra
// - Fixed bug where non-sighted particle systems weren't being drawn for players on the ground (bug #127)
//
// Revision 1.51 2002/07/08 17:07:56 Flayra
// - Started to add display of marine upgrade sprite, fixed bug where building indicators aren't displayed after a map change, info_location drawing changes, primal scream color tweak, removed old hive drawing code
//
// Revision 1.50 2002/07/01 21:35:05 Flayra
// - Removed lots of outdated sprites and sprite code, added building ranges, fixed ghost building problem (bug #82)
//
// Revision 1.49 2002/06/25 18:03:09 Flayra
// - Added info_locations, removed old weapon help system, added smooth resource swelling, lots of alien UI usability changes, fixed problem with ghost building
//
// Revision 1.48 2002/06/10 19:55:36 Flayra
// - New commander UI (bindable via hotkeys, added REMOVE_SELECTION for when clicking menu options when no players selected)
//
// Revision 1.47 2002/06/03 16:48:45 Flayra
// - Help sprites moved into one animated sprite, select sound volume reduced (now that sound is normalized)
//
// Revision 1.46 2002/05/28 17:48:14 Flayra
// - Minimap refactoring, reinforcement refactoring, new hive sight fixes, recycling support
//
// Revision 1.45 2002/05/23 02:33:42 Flayra
// - Post-crash checkin. Restored @Backup from around 4/16. Contains changes for last four weeks of development.
//
//===============================================================================
#include "mod/AvHConstants.h"
#include "mod/AvHHud.h"
#include "cl_dll/hud.h"
#include "cl_dll/cl_util.h"
#include "vgui_label.h"
#include "ui/PieMenu.h"
#include "mod/AvHTeamHierarchy.h"
#include "mod/AvHPieMenuHandler.h"
#include "mod/AvHParticleTemplateClient.h"
#include "mod/AvHParticleSystemManager.h"
#include "mod/AvHClientVariables.h"
#include "mod/AvHSpecials.h"
#include "ui/FadingImageLabel.h"
#include "mod/AvHScrollHandler.h"
#include "mod/AvHEvents.h"
#include "pm_shared/pm_shared.h"
#include "common/cl_entity.h"
#include "mod/AvHCommanderModeHandler.h"
#include "mod/AvHParticleEditorHandler.h"
#include "mod/AvHTechTree.h"
#include "mod/AvHMovementUtil.h"
#include "mod/AvHTitles.h"
#include "mod/AvHSelectionHelper.h"
#include "mod/AvHActionButtons.h"
#include "pm_shared/pm_debug.h"
#include "util/MathUtil.h"
#include "util/STLUtil.h"
#include "mod/AvHSharedUtil.h"
#include "common/r_efx.h"
#include "cl_dll/eventscripts.h"
#include <stdlib.h>
#include "mod/AvHSprites.h"
#include "ui/UIUtil.h"
#include "mod/AvHMiniMap.h"
#include "types.h"
#include <signal.h>
#include "common/event_api.h"
#include "mod/AvHHulls.h"
#include "common/com_model.h"
#include "mod/AvHBasePlayerWeaponConstants.h"
#include "cl_dll/vgui_ScorePanel.h"
#include "mod/AvHAlienAbilityConstants.h"
#include "mod/AvHSharedUtil.h"
#include "mod/AvHScriptManager.h"
#include "mod/AvHHudConstants.h"
#include "cl_dll/demo.h"
#include "common/demo_api.h"
#include "cl_dll/ammohistory.h"
#include "mod/AvHTechImpulsePanel.h"
#include "mod/AvHServerVariables.h"
#include "mod/AvHPlayerUpgrade.h"
#include "mod/AvHCommandConstants.h"
#include "mod/AvHDebugUtil.h"
#include "engine/keydefs.h"
#include "ui/ChatPanel.h"
#include "cl_dll/r_studioint.h"
#include "util/Tokenizer.h"
#include <sstream>
#include "mod/AvHNetworkMessages.h"
//#include "cl_dll/studio_util.h"
//#include "cl_dll/r_studioint.h"
void IN_GetMousePos( int *mx, int *my );
extern playermove_t *pmove;
void RemoveAllDecals();
void ScorePanel_InitializeDemoRecording();
// Include windows for GDI and gamma functions
#include "windows.h"
extern engine_studio_api_t IEngineStudio;
AvHPieMenuHandler gPieMenuHandler;
AvHScrollHandler gScrollHandler;
AvHCommanderModeHandler gCommanderHandler;
AvHParticleEditorHandler gParticleEditorHandler;
extern AvHParticleTemplateListClient gParticleTemplateList;
extern DebugPointListType gTriDebugLocations;
extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1];
extern WeaponsResource gWR;
extern double gClientTimeLastUpdate;
extern "C" Vector gPredictedPlayerOrigin;
extern "C" Vector gPredictedPlayerVOfs;
extern void __CmdFunc_Close(void);
extern int CL_ButtonBits(int);
extern int g_iVisibleMouse;
GammaTable AvHHud::sPregameGammaTable;
GammaTable AvHHud::sGameGammaTable;
bool AvHHud::sShowMap = false;
// Global because of global HUD complilation error
AvHMiniMap gMiniMap;
#include "VGUI_RepaintSignal.h"
//extern vec3_t v_origin;
//extern vec3_t v_angles;
//vec3_t gPlayerOrigin;
//vec3_t gPlayerAngles;
extern AvHSelectionHelper gSelectionHelper;
//#if defined( AVH_CLIENT )
//extern "C" float gOverwatchTargetRange;
extern float gOverwatchTargetRange;
//#endif
extern bool gResetViewAngles;
extern vec3_t gViewAngles;
extern char sDebugString[128];
float kOverwatchFlashInterval = 2.5f;
const float kReticleInfoMaxAlpha = 50;
int gVisibleMouse = 0;
//voogru: cvar pointers, these should always remain valid once they are set.
cvar_t *gl_monolights = NULL;
cvar_t *gl_overbright = NULL;
cvar_t *gl_clear = NULL;
cvar_t *hud_draw = NULL;
cvar_t *r_drawviewmodel = NULL;
extern cvar_t *cl_movespeedkey;
cvar_t *gl_d3dflip = NULL;
cvar_t *s_show = NULL;
cvar_t *lightgamma = NULL;
cvar_t *r_detailtextures = NULL;
cvar_t *gl_max_size = NULL;
const AvHMapExtents& GetMapExtents()
{
return gHUD.GetMapExtents();
}
NumericalInfoEffect::NumericalInfoEffect(float inPosition[3], float inNumber, int inEventType, float inTimeCreated)
{
this->mPosition[0] = inPosition[0];
this->mPosition[1] = inPosition[1];
this->mPosition[2] = inPosition[2];
this->mNumber = inNumber;
this->mEventType = inEventType;
this->mTimeCreated = inTimeCreated;
}
void NumericalInfoEffect::GetPosition(float* outPosition) const
{
outPosition[0] = this->mPosition[0];
outPosition[1] = this->mPosition[1];
outPosition[2] = this->mPosition[2];
}
float NumericalInfoEffect::GetNumber() const
{
return this->mNumber;
}
int NumericalInfoEffect::GetEventType() const
{
return this->mEventType;
}
float NumericalInfoEffect::GetTimeCreated() const
{
return this->mTimeCreated;
}
void NumericalInfoEffect::SetPosition(float inPosition[3])
{
this->mPosition[0] = inPosition[0];
this->mPosition[1] = inPosition[1];
this->mPosition[2] = inPosition[2];
}
void AvHHud::OnActivateSteamUI()
{
// Set the normal gamma so the Steam UI looks correct.
sPregameGammaTable.InitializeToVideoState();
mSteamUIActive = true;
}
void AvHHud::OnDeactivateSteamUI()
{
// Set the special NS gamma.
SetGamma(mDesiredGammaSlope);
mSteamUIActive = false;
// The Steam UI screws up the mouse cursor so reset it.
if (gViewPort != NULL)
{
gViewPort->UpdateCursorState();
}
}
void AvHHud::OnLostFocus()
{
sPregameGammaTable.InitializeToVideoState();
}
bool AvHHud::OnKeyEvent(int virtualKey, int scanCode, bool pressed)
{
if (gViewPort != NULL && !mSteamUIActive)
{
ChatPanel* theChatPanel = gViewPort->GetChatPanel();
if (theChatPanel && theChatPanel->isVisible())
{
if (pressed)
{
theChatPanel->KeyDown(virtualKey, scanCode);
return true;
}
else
{
// If the key wasn't pressed while the chat window was open,
// the key up needs to go to HL.
return theChatPanel->WasKeyPushed(virtualKey);
}
}
if (virtualKey == VK_ESCAPE && GetInTopDownMode() && mGhostBuilding != MESSAGE_NULL)
{
if (pressed)
{
CancelBuilding();
}
return true;
}
}
return false;
}
int AvHHud::GetGameTime() const
{
int theGameTime = 0;
if(this->mGameTime > 0)
{
theGameTime = (int)(this->mGameTime);
}
return theGameTime;
}
int AvHHud::GetGameTimeLimit() const
{
return this->mTimeLimit;
}
int AvHHud::GetCombatAttackingTeamNumber() const
{
return this->mCombatAttackingTeamNumber;
}
bool AvHHud::GetShowingMap()
{
return sShowMap;
}
bool AvHHud::GetGameStarted() const
{
return (this->mGameTime >= 0) && !this->mGameEnded;
}
bool AvHHud::GetIsAlive(bool inIncludeSpectating) const
{
bool theIsAlive = false;
cl_entity_s* thePlayer = gEngfuncs.GetLocalPlayer();
if(inIncludeSpectating)
{
thePlayer = this->GetVisiblePlayer();
}
if(thePlayer)
{
int thePlayerIndex = thePlayer->index;
if((thePlayerIndex) && (thePlayerIndex <= MAX_PLAYERS))
{
int thePlayerClass = g_PlayerExtraInfo[thePlayerIndex].playerclass;
switch(thePlayerClass)
{
case PLAYERCLASS_ALIVE_MARINE:
case PLAYERCLASS_ALIVE_HEAVY_MARINE:
case PLAYERCLASS_ALIVE_JETPACK_MARINE:
case PLAYERCLASS_ALIVE_LEVEL1:
case PLAYERCLASS_ALIVE_LEVEL2:
case PLAYERCLASS_ALIVE_LEVEL3:
case PLAYERCLASS_ALIVE_LEVEL4:
case PLAYERCLASS_ALIVE_LEVEL5:
case PLAYERCLASS_ALIVE_DIGESTING:
case PLAYERCLASS_ALIVE_GESTATING:
case PLAYERCLASS_COMMANDER:
theIsAlive = true;
}
}
}
return theIsAlive;
}
bool GetIsWithinRegion(float inNormX, float inNormY, float inLowX, float inLowY, float inHighX, float inHighY)
{
bool inRegion = false;
if((inNormX >= inLowX) && (inNormY >= inLowY) && (inNormX <= inHighX) && (inNormY < inHighY))
{
inRegion = true;
}
return inRegion;
}
bool AvHHud::GetIsRegionBlockedByUI(float inNormX, float inNormY)
{
bool theIsBlocked = true;
if( GetIsWithinRegion(inNormX, inNormY, 0, .061, .3017, .6797) ||
GetIsWithinRegion(inNormX, inNormY, .248, .0791, .7753, .6823) ||
GetIsWithinRegion(inNormX, inNormY, .748, .092, 1, .6575) ||
GetIsWithinRegion(inNormX, inNormY, .751, .645, .870, .678) ||
GetIsWithinRegion(inNormX, inNormY, .337, .679, .729, .754) ||
GetIsWithinRegion(inNormX, inNormY, .337, .717, .703, .823) )
{
theIsBlocked = false;
// Now check pending requests (the only HUD element not drawn as part of the outlying frame
for(PendingRequestListType::const_iterator theIterator = this->mPendingRequests.begin(); theIterator != this->mPendingRequests.end(); theIterator++)
{
AvHMessageID theMessageID = theIterator->first;
char theComponentName[256];
sprintf(theComponentName, kPendingImpulseSpecifier, (int)theMessageID);
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(theComponentName, theTechImpulsePanel))
{
int thePosX, thePosY;
theTechImpulsePanel->getPos(thePosX, thePosY);
int theWidth, theHeight;
theTechImpulsePanel->getSize(theWidth, theHeight);
int theHighX = thePosX + theWidth;
int theHighY = thePosY + theHeight;
float theScreenWidth = ScreenWidth();
float theScreenHeight = ScreenHeight();
if(GetIsWithinRegion(inNormX, inNormY, thePosX/theScreenWidth, thePosY/theScreenHeight, theHighX/theScreenWidth, theHighY/theScreenHeight))
{
theIsBlocked = true;
break;
}
}
}
}
return theIsBlocked;
}
bool AvHHud::GetIsShowingMap() const
{
return sShowMap;
}
void AvHHud::ClearSelection()
{
gSelectionHelper.ClearSelection();
this->mGroupEvent = COMMANDER_REMOVESELECTION;
}
void CLinkGhostBuildingCallback( struct tempent_s *ent, float frametime, float currenttime)
{
gHUD.GhostBuildingCallback(ent, frametime, currenttime);
}
// For easily adding message functions
#define BIND_MESSAGE(x) \
int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \
{ \
return gHUD.##x(pszName, iSize, pbuf ); \
}
AvHHud::AvHHud(const string& inFilename, UIFactory* inFactory) : UIHud(inFilename, inFactory)
{
this->ClearData();
mSteamUIActive = false;
}
void AvHHud::AddNumericalInfoMessage(float inOrigin[3], float inNumber, int inEventType)
{
NumericalInfoEffect theEffect(inOrigin, inNumber, inEventType, this->mTimeOfLastUpdate);
this->mNumericalInfoEffects.push_back(theEffect);
}
void AvHHud::AddTooltip(const char* inMessageText, bool inIsToolTip, float inTooltipWidth)
{
if(!gEngfuncs.pDemoAPI->IsPlayingback() && (strlen(inMessageText) > 0))
{
if(gEngfuncs.pfnGetCvarFloat(kvAutoHelp) || !inIsToolTip)
{
AvHTooltip theNewTooltip;
theNewTooltip.SetText(string(inMessageText));
theNewTooltip.SetNormalizedScreenX(1.0f - inTooltipWidth - kHelpMessageLeftEdgeInset);
theNewTooltip.SetNormalizedScreenY(0.01f);
theNewTooltip.SetCentered(false);
theNewTooltip.SetIgnoreFadeForLifetime(true);
theNewTooltip.SetNormalizedMaxWidth(inTooltipWidth);
if(inIsToolTip)
{
this->PlayHUDSound(HUD_SOUND_TOOLTIP);
}
this->mTooltips.push_back(theNewTooltip);
}
}
}
bool AvHHud::AddTooltipOnce(const char* inMessageText, bool inIsToolTip)
{
bool theAddedTooltip = false;
string theMessage(inMessageText);
// Check if message is in sent list
StringList::iterator theIter = std::find(this->mDisplayedToolTipList.begin(), this->mDisplayedToolTipList.end(), theMessage);
if(theIter == this->mDisplayedToolTipList.end())
{
// If not
// Call AddTooltip
this->AddTooltip(inMessageText, inIsToolTip);
theAddedTooltip = true;
// Add message to list
this->mDisplayedToolTipList.push_back(theMessage);
}
return theAddedTooltip;
}
void AvHHud::Cancel(void)
{
ASSERT(this->mInTopDownMode);
gCommanderHandler.CancelHit();
}
void AvHHud::ClearData()
{
this->mResources = 0;
this->mHierarchy = NULL;
this->mShowMapHierarchy = NULL;
this->mCommanderResourceLabel = NULL;
this->mGenericProgressBar = NULL;
this->mResearchProgressBar = NULL;
this->mAlienProgressBar = NULL;
this->mResearchLabel = NULL;
//this->mArmorLevel = ARMOR_BASE;
this->mTimeOfLastUpdate = 0.0;
this->mTimeOfNextHudSound = -1;
this->mLastHUDSoundPlayed = HUD_SOUND_INVALID;
this->mTimeOfLastEntityUpdate = -1;
this->mInTopDownMode = false;
this->mLeftMouseStarted = false;
this->mLeftMouseEnded = false;
this->mPlacingBuilding = false;
this->mRightMouseStarted = false;
this->mRightMouseEnded = false;
//this->mOrderMode = ORDERTYPE_UNDEFINED;
this->mTechEvent = MESSAGE_NULL;
this->mAlienAbility = MESSAGE_NULL;
this->mGroupEvent = MESSAGE_NULL;
this->mTrackingEntity = 0;
this->mNumLocalSelectEvents = 0;
this->mSelected.clear();
this->mSelectionJustChanged = false;
this->mMouseOneDown = false;
this->mMouseTwoDown = false;
this->mMouseOneStartX = 0;
this->mMouseOneStartY = 0;
this->mMouseTwoStartX = 0;
this->mMouseTwoStartY = 0;
this->mMouseCursorX = this->mMouseCursorY = 0;
this->mPieMenuControl = "";
this->mPreviousHelpText = "";
this->mTimeLastHelpTextChanged = -1;
this->mCurrentCursorFrame = 0;
this->mMapExtents.ResetMapExtents();
this->mMapName = "";
this->mGhostBuilding = MESSAGE_NULL;
this->mValidatedBuilding = MESSAGE_NULL;
this->mCreatedGhost = false;
this->mCurrentGhostIsValid = false;
this->mAmbientSounds.clear();
// tankefugl: 0000971
this->mTeammateOrder.clear();
this->mDisplayOrderIndex = 0;
this->mDisplayOrderTime = 0;
this->mDisplayOrderType = 0;
// :tankefugl
}
AvHHud::~AvHHud(void)
{
//this->ResetGamma();
//delete [] sOriginalGammaTable;
//delete [] sGammaTable;
AvHHud::ResetGammaAtExit();
}
void DummyFunction()
{
}
#ifdef DEBUG
int gGlobalDebugAuth = 0;
void TestIcon()
{
gGlobalDebugAuth = rand() % 7;
}
typedef struct alias_t {
alias_t* next;
char name[32];
char* cmds;
} alias_s;
void TestAlias()
{
alias_s* alias = *(alias_s**)0x2D5929C;
while(alias)
{
gEngfuncs.Con_Printf("name: %s\n%x - %x\n", alias->name, alias->name, gEngfuncs);
alias = alias->next;
}
}
#endif
// Used for console command
void AvHHud::PlayRandomSongHook()
{
gHUD.PlayRandomSong();
}
void AvHHud::AddCommands()
{
gEngfuncs.pfnAddCommand ("+popupmenu", AvHPieMenuHandler::OpenPieMenu);
gEngfuncs.pfnAddCommand ("-popupmenu", AvHPieMenuHandler::ClosePieMenu);
gEngfuncs.pfnAddCommand ("+mousepopupmenu", AvHPieMenuHandler::OpenPieMenu);
gEngfuncs.pfnAddCommand ("-mousepopupmenu", AvHPieMenuHandler::ClosePieMenu);
// Add scrolling commands
gEngfuncs.pfnAddCommand ("+scrollup", AvHScrollHandler::ScrollUp);
gEngfuncs.pfnAddCommand ("-scrollup", AvHScrollHandler::StopScroll);
gEngfuncs.pfnAddCommand ("+scrolldown", AvHScrollHandler::ScrollDown);
gEngfuncs.pfnAddCommand ("-scrolldown", AvHScrollHandler::StopScroll);
gEngfuncs.pfnAddCommand ("+scrollleft", AvHScrollHandler::ScrollLeft);
gEngfuncs.pfnAddCommand ("-scrollleft", AvHScrollHandler::StopScroll);
gEngfuncs.pfnAddCommand ("+scrollright", AvHScrollHandler::ScrollRight);
gEngfuncs.pfnAddCommand ("-scrollright", AvHScrollHandler::StopScroll);
gEngfuncs.pfnAddCommand ("toggleeditps", AvHParticleEditorHandler::ToggleEdit);
gEngfuncs.pfnAddCommand ("nexttrack", AvHHud::PlayRandomSongHook);
gEngfuncs.pfnAddCommand ("+showmap", AvHHud::ShowMap);
gEngfuncs.pfnAddCommand ("-showmap", AvHHud::HideMap);
gEngfuncs.pfnAddCommand ("playstream", AvHHud::PlayStream);
gEngfuncs.pfnAddCommand ("stopstream", AvHHud::StopStream);
#ifdef DEBUG
gEngfuncs.pfnAddCommand("testicon", TestIcon);
gEngfuncs.pfnAddCommand("testalias", TestAlias);
#endif
int i = 0;
char theBinding[128];
for(i = (int)(RESOURCE_UPGRADE); i <= (int)(BUILD_RECYCLE); i++)
{
sprintf(theBinding, "%s%d", kHotKeyPrefix, i);
gEngfuncs.pfnAddCommand(theBinding, DummyFunction);
}
for(i = (int)(MENU_BUILD); i <= (int)(MENU_EQUIP); i++)
{
sprintf(theBinding, "%s%d", kHotKeyPrefix, i);
gEngfuncs.pfnAddCommand(theBinding, DummyFunction);
}
}
void AvHHud::ClientProcessEntity(struct entity_state_s* inEntity)
{
// Check if we need to create or destroy particle systems
int theIndex = inEntity->number;
bool theParticleOn = inEntity->iuser3 == AVH_USER3_PARTICLE_ON;
bool theParticleOff = inEntity->iuser3 == AVH_USER3_PARTICLE_OFF;
if(theParticleOn || theParticleOff)
{
int theHandle = -1;
if(theParticleOn)
{
// Ent index and template index stored in fuser1
int theValue = (int)(inEntity->fuser1);
int theGenEntIndex = (0xFFFF0000 & theValue) >> 16;
//int theTemplateIndex = (0x0000FFFF & theValue);
int theTemplateIndex = (((int(inEntity->fuser1)) & 0x0000FF00) >> 8);
//int theTemplateIndex = theValue;
// Handle stored in fuser2
theHandle = (int)(inEntity->fuser2);
// Don't create particle systems marked as high-detail if we don't have that option set. Note, this could cause collision
// differences between the client and server if the particle system doesn't use this flag with care
const AvHParticleTemplate* theTemplate = gParticleTemplateList.GetTemplateAtIndex(theTemplateIndex);
if(theTemplate)
{
if(!theTemplate->GetHighDetailOnly() || gEngfuncs.pfnGetCvarFloat(kvHighDetail))
{
AvHParticleSystemManager::Instance()->CreateParticleSystemIfNotCreated(inEntity->number, theTemplateIndex, /*theEntIndex,*/ theHandle);
// Update postion and visibility
if(theGenEntIndex > 0)
{
cl_entity_s* theGenEntity = gEngfuncs.GetEntityByIndex(theGenEntIndex);
if(theGenEntity)
{
AvHParticleSystemManager::Instance()->SetParticleSystemGenerationEntityExtents(theGenEntity->curstate.mins, theGenEntity->curstate.maxs, theHandle);
}
}
else
{
AvHParticleSystemManager::Instance()->SetParticleSystemPosition(inEntity->origin, theHandle);
}
// Set the particle system custom data
//uint16 theCustomData = (uint16)(((int)inEntity->fuser3) >> 16);
//uint16 theCustomData = (uint16)(inEntity->fuser3);
uint16 theCustomData = (uint16)(inEntity->weaponmodel);
AvHParticleSystemManager::Instance()->SetParticleSystemCustomData(theCustomData, theHandle);
}
}
}
else if(theParticleOff)
{
theHandle = (int)(inEntity->fuser1);
//AvHParticleSystemManager::Instance()->DestroyParticleSystemIfNotDestroyed(inEntity->number, theHandle);
AvHParticleSystemManager::Instance()->MarkParticleSystemForDeletion(inEntity->number, theHandle);
}
// Always update visibility
bool theVisibilityState = false;
if(this->GetInTopDownMode())
{
if(GetHasUpgrade(inEntity->iuser4, MASK_VIS_SIGHTED))
{
theVisibilityState = true;
}
else
{
theVisibilityState = false;
}
}
else
{
theVisibilityState = true;
}
AvHParticleSystemManager::Instance()->SetParticleSystemVisibility(theVisibilityState, theHandle);
}
else if((inEntity->iuser3 == AVH_USER3_AUDIO_ON) || (inEntity->iuser3 == AVH_USER3_AUDIO_OFF))
{
// Read values
int theEntIndex = (int)(inEntity->fuser1) >> 16;
//int theSoundIndex = (int)(inEntity->fuser1) & 0x0000FFFF;
// memcpy so value isn't interpreted
//int theSoundIndex = 0;
//memcpy(&theSoundIndex, &inEntity->fuser1, sizeof(float));
//theSoundIndex = theSoundIndex & 0x0000FFFF;
int theSoundIndex = (((int(inEntity->fuser1)) & 0x0000FF00) >> 8);
// Top byte is flags, next byte is volume, bottom two bytes are fade distance
int theFlags = inEntity->iuser4 >> 24;
int theVolume = (inEntity->iuser4 >> 16) & 0x00FF;
int theFadeDistance = (inEntity->iuser4) & 0x0000FFFF;
float theTimeOfAction = inEntity->fuser2;
bool theSoundOn = (inEntity->iuser3 == AVH_USER3_AUDIO_ON);
this->ModifyAmbientSoundEntryIfChanged(theSoundOn, theSoundIndex, theEntIndex, theTimeOfAction, theVolume, theFadeDistance, theFlags, inEntity->origin);
}
}
string LookupAndTranslate(AvHMessageID inMessageID)
{
string theKey = string(kTechNodeLabelPrefix) + MakeStringFromInt((int)inMessageID);
string theTranslatedTechName;
LocalizeString(theKey.c_str(), theTranslatedTechName);
return theTranslatedTechName;
}
void AvHHud::DisplayCombatUpgradeMenu(bool inVisible)
{
if(inVisible)
{
// Parse current tech nodes and set text
const AvHTechID kLineStart[kNumUpgradeLines] = {TECH_ONE_LEVEL_ONE, TECH_TWO_LEVEL_ONE, TECH_THREE_LEVEL_ONE, TECH_FOUR_LEVEL_ONE, TECH_FIVE_LEVEL_ONE};
// Add "you are now x"!
string theYouAreNow;
LocalizeString(kYouAreNowA, theYouAreNow);
string theRankTitle = this->GetRankTitle(false);
string theExclamation;
LocalizeString(kExclamation, theExclamation);
string theChooseAnUpgrade;
LocalizeString(kChooseAnUpgrade, theChooseAnUpgrade);
string theFinalText = theYouAreNow + string(" ") + theRankTitle + theExclamation + string("\n");
theFinalText += theChooseAnUpgrade + string("\n\n");
// Set the lines
this->mCombatUpgradeMenu.SetText(theFinalText);
}
// Parse text above every time, but only set position once so it doesn't keep animating
if(inVisible && !this->mDrawCombatUpgradeMenu)
{
// Start off screen, and scroll right
const float kWidth = .4f;
this->mCombatUpgradeMenu.SetNormalizedScreenX(-kWidth);
this->mCombatUpgradeMenu.SetNormalizedScreenY(.25f);
this->mCombatUpgradeMenu.SetNormalizedMaxWidth(kWidth);
}
this->mDrawCombatUpgradeMenu = inVisible;
}
void AvHHud::DisplayMessage(const char* inMessage)
{
this->m_Message.MessageAdd(inMessage, this->m_flTime);
// Remember the time -- to fix up level transitions
//this->m_Message.m_parms.time = this->m_flTime;
// Turn on drawing
if ( !(this->m_Message.m_iFlags & HUD_ACTIVE) )
this->m_Message.m_iFlags |= HUD_ACTIVE;
}
//int AvHHud::GetArmorLevel(void) const
//{
// return this->mArmorLevel;
//}
int AvHHud::GetFrameForOrderType(AvHOrderType inOrderType) const
{
int theFrame = 0;
switch(inOrderType)
{
case ORDERTYPEL_DEFAULT:
theFrame = 2;
break;
case ORDERTYPEL_MOVE:
theFrame = 2;
break;
case ORDERTYPET_ATTACK:
theFrame = 4;
break;
case ORDERTYPET_BUILD:
theFrame = 5;
break;
case ORDERTYPET_GUARD:
theFrame = 6;
break;
case ORDERTYPET_WELD:
theFrame = 7;
break;
case ORDERTYPET_GET:
theFrame = 8;
break;
}
return theFrame;
}
AvHPlayMode AvHHud::GetPlayMode(void) const
{
AvHPlayMode thePlayMode = PLAYMODE_UNDEFINED;
cl_entity_s* thePlayer = gEngfuncs.GetLocalPlayer();
if(thePlayer)
{
if(gEngfuncs.IsSpectateOnly())
{
thePlayMode = PLAYMODE_OBSERVER;
}
else
{
thePlayMode = AvHPlayMode(thePlayer->curstate.playerclass);
}
}
return thePlayMode;
}
AvHPlayMode AvHHud::GetHUDPlayMode() const
{
AvHPlayMode thePlayMode = this->GetPlayMode();
cl_entity_s* thePlayer = this->GetVisiblePlayer();
if(thePlayer)
{
thePlayMode = AvHPlayMode(thePlayer->curstate.playerclass);
}
return thePlayMode;
}
cl_entity_s* AvHHud::GetVisiblePlayer() const
{
cl_entity_s* thePlayer = gEngfuncs.GetLocalPlayer();
if(g_iUser1 == OBS_IN_EYE)
{
cl_entity_t* theEnt = gEngfuncs.GetEntityByIndex(g_iUser2);
if(theEnt)
{
thePlayer = theEnt;
}
}
return thePlayer;
}
int AvHHud::GetLocalUpgrades() const
{
static int theUpgrades = 0;
cl_entity_s* thePlayer = this->GetVisiblePlayer();
if(thePlayer)
{
theUpgrades = thePlayer->curstate.iuser4;
}
return theUpgrades;
}
// Players could hack their client dll and see all the orders on their team. Minor cheat but definitely possible.
EntityListType AvHHud::GetDrawPlayerOrders() const
{
EntityListType theList;
cl_entity_s* theVisiblePlayer = this->GetVisiblePlayer();
if(theVisiblePlayer)
{
int theVisiblePlayerIndex = theVisiblePlayer->index;
if(this->GetHUDUser3() == AVH_USER3_MARINE_PLAYER)
{
// Only draw orders for us
theList.push_back(theVisiblePlayerIndex);
}
else if(this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER)
{
// Add everyone that he has selected!
return this->mSelected;
}
}
return theList;
}
bool AvHHud::GetInTopDownMode() const
{
return this->mInTopDownMode;
}
bool AvHHud::GetIsSelecting() const
{
return mSelectionBoxVisible;
}
OrderListType AvHHud::GetOrderList() const
{
return this->mOrders;
}
//AvHOrderType AvHHud::GetOrderMode() const
//{
// return this->mOrderMode;
//}
bool AvHHud::GetCenterPositionForGroup(int inGroupNumber, vec3_t& outCenterPosition) const
{
bool theSuccess = false;
if((inGroupNumber >= 1) && (inGroupNumber <= kNumHotkeyGroups))
{
vec3_t theCenterPosition;
VectorClear(theCenterPosition);
int theNumFound = 0;
const EntityListType& theGroup = this->mGroups[inGroupNumber - 1];
if(theGroup.size() > 0)
{
for(EntityListType::const_iterator theIter = theGroup.begin(); theIter != theGroup.end(); theIter++)
{
int theEntIndex = *theIter;
Vector thePosition;
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(theEntIndex);
if(theEntity)
{
thePosition = theEntity->curstate.origin;
}
if(AvHSHUGetEntityLocation(theEntIndex, thePosition))
{
theCenterPosition.x += thePosition.x;
theCenterPosition.y += thePosition.y;
theNumFound++;
}
}
if(theNumFound > 0)
{
theCenterPosition.x /= theNumFound;
theCenterPosition.y /= theNumFound;
outCenterPosition = theCenterPosition;
theSuccess = true;
}
}
}
return theSuccess;
}
void AvHHud::GetMousePos(int& outX, int& outY) const
{
gEngfuncs.GetMousePosition(&outX, &outY);
// Clip mouse to window (weird)
outX = min(max(0, outX), ScreenWidth());
outY = min(max(0, outY), ScreenHeight());
//char theMouseMessage[256];
//sprintf(theMouseMessage, "Mouse coords: %d, %d", outX, outY);
//CenterPrint(theMouseMessage);
}
bool AvHHud::GetAndClearTopDownScrollAmount(int& outX, int& outY, int& outZ)
{
bool theSuccess = false;
outX = 0;
outY = 0;
outZ = 0;
// Don't scroll if the the commander is dragging a selection box.
if(this->GetInTopDownMode() && !GetIsSelecting())
{
const int kScreenWidth = ScreenWidth();
const int kScreenHeight = ScreenHeight();
const kScrollHorizontal = .0152f*kScreenWidth;
const kScrollVertical = .015f*kScreenHeight;
// Left side
if(this->GetIsMouseInRegion(0, 0, kScrollHorizontal, kScreenHeight) || (gScrollHandler.GetXScroll() < 0))
{
outX = -1;
}
// Right side
else if(this->GetIsMouseInRegion(kScreenWidth - kScrollHorizontal, 0, kScrollHorizontal, kScreenHeight) || (gScrollHandler.GetXScroll() > 0))
{
outX = 1;
}
// Top edge
if(this->GetIsMouseInRegion(0, 0, kScreenWidth, kScrollVertical) || (gScrollHandler.GetYScroll() > 0))
{
outY = 1;
}
// Bottom edge
else if(this->GetIsMouseInRegion(0, kScreenHeight - kScrollVertical, kScreenWidth, kScrollVertical) || (gScrollHandler.GetYScroll() < 0))
{
outY = -1;
}
// Only clear z scroll because of the way events work (invnext/invprev vs. holding a key down)
//gScrollHandler.ClearScrollHeight();
theSuccess = true;
}
return theSuccess;
}
bool AvHHud::GetAndClearSelectionEvent(vec3_t& outSelection, AvHMessageID& outMessageID)
{
bool theSuccess = false;
// Return a build event if there is one, else return a COMMANDER_MOUSECOORD event
if(this->mLeftMouseStarted)
{
if(this->mValidatedBuilding == MESSAGE_NULL)
{
VectorCopy(this->mLeftMouseWorldStart, outSelection);
outMessageID = COMMANDER_MOUSECOORD;
}
else
{
VectorCopy(this->mNormBuildLocation, outSelection);
outMessageID = this->mValidatedBuilding;
this->mValidatedBuilding = this->mGhostBuilding = MESSAGE_NULL;
this->mPlacingBuilding = true;
}
theSuccess = true;
}
else if(this->mLeftMouseEnded)
{
if(!this->mPlacingBuilding)
{
outSelection = this->mLeftMouseWorldEnd;
outMessageID = COMMANDER_MOUSECOORD;
theSuccess = true;
}
this->mPlacingBuilding = false;
}
else if(this->mRightMouseStarted)
{
// Cancel building placement
if(this->mGhostBuilding != MESSAGE_NULL)
{
CancelBuilding();
}
else
{
outSelection = this->mRightMouseWorldStart;
outMessageID = COMMANDER_MOUSECOORD;
theSuccess = true;
}
}
else if(this->mRightMouseEnded)
{
outSelection = this->mRightMouseWorldEnd;
outMessageID = COMMANDER_MOUSECOORD;
theSuccess = true;
}
else
{
outSelection = this->mMouseWorldPosition;
outMessageID = COMMANDER_MOUSECOORD;
theSuccess = true;
}
return theSuccess;
}
EntityListType AvHHud::GetSelected() const
{
return this->mSelected;
}
const AvHTechSlotManager& AvHHud::GetTechSlotManager() const
{
return this->mTechSlotManager;
}
bool AvHHud::GetAndClearAlienAbility(AvHMessageID& outMessageID)
{
bool theAlienAbilityWaiting = false;
if(this->mAlienAbility != MESSAGE_NULL)
{
outMessageID = this->mAlienAbility;
theAlienAbilityWaiting = true;
this->mAlienAbility = MESSAGE_NULL;
}
return theAlienAbilityWaiting;
}
bool AvHHud::GetAndClearGroupEvent(AvHMessageID& outMessageID)
{
bool theGroupEventWaiting = false;
if(this->mGroupEvent != MESSAGE_NULL)
{
outMessageID = this->mGroupEvent;
theGroupEventWaiting = true;
// if(!this->mIsTracking)
// {
this->mGroupEvent = MESSAGE_NULL;
// }
}
return theGroupEventWaiting;
}
int AvHHud::GetTrackingEntity() const
{
return this->mTrackingEntity;
}
void AvHHud::ClearTrackingEntity()
{
this->mTrackingEntity = 0;
}
void AvHHud::SetSelectionEffects(EntityListType& inUnitList)
{
// Make sure we have an effect created for each unit in this list. If there are units that
// have selection effects that aren't in this list, delete them. This is called locally when the
// selection is predicted, then it's called again when the selection is confirmed.
this->mSelectionEffects.clear();
for(EntityListType::iterator theIter = inUnitList.begin(); theIter != inUnitList.end(); theIter++)
{
SelectionEffect theNewEffect;
theNewEffect.mEntIndex = *theIter;
theNewEffect.mAngleOffset = 0;
this->mSelectionEffects.push_back(theNewEffect);
}
}
UIMode AvHHud::GetUIMode() const
{
return this->mCurrentUIMode;
}
bool AvHHud::SwitchUIMode(UIMode inNewMode)
{
bool theSuccess = false;
// Only allow switching to a non-main mode when we're in main, always allow switching back to main mode
if((inNewMode == MAIN_MODE) || (this->mCurrentUIMode == MAIN_MODE))
{
if(inNewMode != this->mCurrentUIMode)
{
// Move pop-up menu components away or back so they don't block other compoments...ugh
if(inNewMode != MAIN_MODE)
{
gHUD.GetManager().TranslateComponent(kSoldierMenu, true);
gHUD.GetManager().TranslateComponent(kSoldierCombatMenu, true);
gHUD.GetManager().TranslateComponent(kAlienMenu, true);
gHUD.GetManager().TranslateComponent(kAlienCombatMenu, true);
gHUD.GetManager().TranslateComponent(kAlienMembrane, true);
gHUD.GetManager().TranslateComponent(kScroller, true);
gHUD.GetManager().TranslateComponent(kSelectionText, true);
//CenterPrint("Pop-up controls moved off screen");
}
else
{
gHUD.GetManager().TranslateComponent(kSoldierMenu, false);
gHUD.GetManager().TranslateComponent(kSoldierCombatMenu, false);
gHUD.GetManager().TranslateComponent(kAlienMenu, false);
gHUD.GetManager().TranslateComponent(kAlienCombatMenu, false);
gHUD.GetManager().TranslateComponent(kAlienMembrane, false);
gHUD.GetManager().TranslateComponent(kScroller, false);
gHUD.GetManager().TranslateComponent(kSelectionText, false);
//CenterPrint("Pop-up controls moved on screen");
}
this->mCurrentUIMode = inNewMode;
}
theSuccess = true;
}
return theSuccess;
}
bool AvHHud::Update(float inCurrentTime, string& outErrorString)
{
bool theSuccess = false;
if(inCurrentTime > this->mTimeOfLastUpdate)
{
this->mTimeOfCurrentUpdate = inCurrentTime;
// Predict game time
if(this->GetGameStarted())
{
this->mGameTime += (inCurrentTime - this->mTimeOfLastUpdate);
}
AvHParticleSystemManager::Instance()->Start();
// This component must always be visible to allow us to hook mouse cursor sprite drawing
this->ResetComponentsForUser3();
this->UpdateDataFromVuser4(inCurrentTime);
this->UpdateSpectating();
this->GetManager().UnhideComponent(kLastComponent);
this->UpdateDemoRecordPlayback();
theSuccess = UIHud::Update(inCurrentTime, outErrorString);
if(!theSuccess)
{
this->AddTooltip(outErrorString.c_str());
}
this->UpdateProgressBar();
this->UpdateCommonUI();
this->UpdateAlienUI(inCurrentTime);
this->UpdateMarineUI(inCurrentTime);
this->UpdateCountdown(inCurrentTime);
this->UpdateExploitPrevention();
this->UpdateFromEntities(inCurrentTime);
this->UpdateEntityID(inCurrentTime);
this->UpdateHelpText();
this->UpdateTooltips(inCurrentTime);
this->UpdateStructureNotification(inCurrentTime);
this->UpdateMusic(inCurrentTime);
this->UpdatePieMenuControl();
// Reset cursor every tick, update selection may change it
// This cursor is used when we're on the ground for pie menus as well
this->SetCursor(ORDERTYPE_UNDEFINED);
this->UpdateHierarchy();
this->UpdateInfoLocation();
if(this->GetInTopDownMode())
{
this->UpdateSelection();
gCommanderHandler.Update(this->mTechNodes, this->mResources);
// char theDebugString[128];
// sprintf(theDebugString, "norm X/Y: %f, %f", (float)this->mMouseCursorX/ScreenWidth, (float)this->mMouseCursorY/ScreenHeight);
// CenterPrint(theDebugString);
}
else
{
this->ResetTopDownUI();
}
// Update orders
//for(OrderListType::iterator theIter = this->mOrders.begin(); theIter != this->mOrders.end(); theIter++)
//{
// theIter->Update();
//}
this->UpdateTechNodes();
this->UpdateAmbientSounds();
this->UpdateViewModelEffects();
mOverviewMap.UpdateOrders(mOrders, GetDrawPlayerOrders());
mOverviewMap.Update(inCurrentTime);
float theTimePassed = inCurrentTime - this->mTimeOfLastUpdate;
AvHParticleSystemManager::Instance()->Update(theTimePassed);
AvHScriptManager::Instance()->ClientUpdate(theTimePassed);
this->UpdateResources(theTimePassed);
if((this->GetHUDPlayMode() == PLAYMODE_PLAYING) && !this->GetIsAlive())
{
this->mCommanderResourceLabel->setVisible(false);
this->mHierarchy->setVisible(false);
this->mShowMapHierarchy->setVisible(false);
}
if(cl_particleinfo->value)
{
char theDebugText[128];
int theNumVisible = AvHParticleSystemManager::Instance()->GetNumVisibleParticleSystems();
int theNum = AvHParticleSystemManager::Instance()->GetNumberParticleSystems();
int theNumTemplates = gParticleTemplateList.GetNumberTemplates();
sprintf(theDebugText, "(vis, total, list): %d, %d, %d", theNumVisible, theNum, theNumTemplates);
//sprintf(theDebugText, "step interval: %d", pmove->flTimeStepSound);
/*
if(this->mMarineResourceLabel)
{
this->mMarineResourceLabel->setText(theDebugText);
this->mMarineResourceLabel->setVisible(true);
}
*/
}
if(!gEngfuncs.pDemoAPI->IsPlayingback())
{
IN_GetMousePos(&this->mMouseCursorX, &this->mMouseCursorY);
}
// Update user3 and team
this->mLastUser3 = this->GetHUDUser3();
this->mLastTeamNumber = this->GetHUDTeam();
this->mLastPlayMode = this->GetPlayMode();
this->mTimeOfLastUpdate = inCurrentTime;
// Save view origin and angles before we do crazy viewport stuff
// gPlayerOrigin = v_origin;
// gPlayerAngles = v_angles;
}
return theSuccess;
}
//void AvHHud::UpdateSelectionEffects(float inTimePassed)
//{
// // Radians/sec
// const float kSpinRate = 1.5f;
// for(SelectionListType::iterator theIter = this->mSelectionEffects.begin(); theIter != this->mSelectionEffects.end(); theIter++)
// {
// theIter->mAngleOffset = (theIter->mAngleOffset += inTimePassed*kSpinRate) % 360;
// }
//}
bool AvHHud::GetAndClearTechEvent(AvHMessageID& outMessageID)
{
bool theTechEventWaiting = false;
if(this->mTechEvent != MESSAGE_NULL)
{
outMessageID = this->mTechEvent;
theTechEventWaiting = true;
this->mTechEvent = MESSAGE_NULL;
}
return theTechEventWaiting;
}
bool AvHHud::GetLastHotkeySelectionEvent(AvHMessageID& outMessageID)
{
bool theSuccess = false;
switch(this->mLastHotkeySelectionEvent)
{
case GROUP_SELECT_1:
case GROUP_SELECT_2:
case GROUP_SELECT_3:
case GROUP_SELECT_4:
case GROUP_SELECT_5:
outMessageID = this->mLastHotkeySelectionEvent;
theSuccess = true;
break;
}
return theSuccess;
}
void AvHHud::SetLastHotkeySelectionEvent(AvHMessageID inMessageID)
{
switch(inMessageID)
{
case MESSAGE_NULL:
case GROUP_CREATE_1:
case GROUP_CREATE_2:
case GROUP_CREATE_3:
case GROUP_CREATE_4:
case GROUP_CREATE_5:
case GROUP_SELECT_1:
case GROUP_SELECT_2:
case GROUP_SELECT_3:
case GROUP_SELECT_4:
case GROUP_SELECT_5:
case COMMANDER_REMOVESELECTION:
this->mLastHotkeySelectionEvent = inMessageID;
break;
default:
ASSERT(false);
break;
}
}
bool AvHHud::GetIsAlien() const
{
bool theIsAlien = false;
AvHUser3 theUser3 = this->GetHUDUser3();
switch(theUser3)
{
case AVH_USER3_ALIEN_PLAYER1:
case AVH_USER3_ALIEN_PLAYER2:
case AVH_USER3_ALIEN_PLAYER3:
case AVH_USER3_ALIEN_PLAYER4:
case AVH_USER3_ALIEN_PLAYER5:
case AVH_USER3_ALIEN_EMBRYO:
theIsAlien = true;
break;
}
return theIsAlien;
}
bool AvHHud::GetIsBeingDigested() const
{
bool theIsBeingDigested = false;
int theUpgrades = this->GetHUDUpgrades();
if(GetHasUpgrade(theUpgrades, MASK_DIGESTING))
{
cl_entity_t* theVisiblePlayer = this->GetVisiblePlayer();
if(theVisiblePlayer && (theVisiblePlayer->curstate.effects & EF_NODRAW))
{
theIsBeingDigested = true;
}
}
return theIsBeingDigested;
}
bool AvHHud::GetIsEnsnared() const
{
int theUpgrades = this->GetHUDUpgrades();
return GetHasUpgrade(theUpgrades, MASK_ENSNARED);
}
bool AvHHud::GetIsStunned() const
{
int theUpgrades = this->GetHUDUpgrades();
return GetHasUpgrade(theUpgrades, MASK_PLAYER_STUNNED);
}
bool AvHHud::GetIsDigesting() const
{
bool theIsDigesting = false;
int theUpgrades = this->GetHUDUpgrades();
if(GetHasUpgrade(theUpgrades, MASK_DIGESTING))
{
cl_entity_t* theVisiblePlayer = this->GetVisiblePlayer();
if(theVisiblePlayer && !(theVisiblePlayer->curstate.effects & EF_NODRAW))
{
theIsDigesting = true;
}
}
return theIsDigesting;
}
bool AvHHud::GetIsNotInControl() const
{
return GetIsBeingDigested() || !IEngineStudio.IsHardware();
}
bool AvHHud::GetIsInTopDownMode() const
{
bool theIsInTopDownMode = false;
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_TOPDOWN))
{
theIsInTopDownMode = true;
}
return theIsInTopDownMode;
}
int AvHHud::GetCommanderIndex() const
{
int theCommanderIndex = -1;
for(int i = 1; i <= MAX_PLAYERS; i++)
{
extra_player_info_t* theExtraPlayerInfo = &g_PlayerExtraInfo[i];
ASSERT(theExtraPlayerInfo);
int thePlayerClass = theExtraPlayerInfo->playerclass;
if(thePlayerClass == PLAYERCLASS_COMMANDER)
{
theCommanderIndex = i;
break;
}
}
return theCommanderIndex;
}
bool AvHHud::GetHasJetpack() const
{
int theLocalUpgrades = this->GetHUDUpgrades();
bool theHasJetpackUpgrade = GetHasUpgrade(theLocalUpgrades, MASK_UPGRADE_7) && this->GetIsMarine();
return theHasJetpackUpgrade;
}
bool AvHHud::GetHasAlienUpgradesAvailable() const
{
bool theHasUpgradesAvailable = false;
if(this->GetIsAlien() && this->GetIsRelevant() && !this->GetIsBeingDigested())
{
int theUpgradeVar = this->GetLocalUpgrades();
bool theHasDefensiveUpgradesAvailable = AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_DEFENSE, this->mUpgrades, theUpgradeVar);
bool theHasMovementUpgradesAvailable = AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_MOVEMENT, this->mUpgrades, theUpgradeVar);
bool theHasSensoryUpgradesAvailable = AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_SENSORY, this->mUpgrades, theUpgradeVar);
theHasUpgradesAvailable = theHasDefensiveUpgradesAvailable || theHasMovementUpgradesAvailable || theHasSensoryUpgradesAvailable;
}
return theHasUpgradesAvailable;
}
bool AvHHud::GetIsMarine() const
{
bool theIsMarine = false;
AvHUser3 theUser3 = this->GetHUDUser3();
switch(theUser3)
{
case AVH_USER3_MARINE_PLAYER:
case AVH_USER3_COMMANDER_PLAYER:
theIsMarine = true;
break;
}
return theIsMarine;
}
bool AvHHud::GetIsRelevant() const
{
bool theIsRelevant = false;
if(this->GetIsAlive() && (this->GetPlayMode() == PLAYMODE_PLAYING) /*&& !this->GetIsSpectator()*/)
{
theIsRelevant = true;
}
return theIsRelevant;
}
vec3_t AvHHud::GetVisualOrigin() const
{
vec3_t theVisualOrigin = gPredictedPlayerOrigin;
theVisualOrigin.z += gPredictedPlayerVOfs[2];
return theVisualOrigin;
}
AvHMessageID AvHHud::HotKeyHit(char inChar)
{
return gCommanderHandler.HotKeyHit(inChar);
}
float AvHHud::GetGammaSlope() const
{
return sGameGammaTable.GetGammaSlope();
}
string AvHHud::GetMapName(bool inLocalOnly) const
{
string theMapName = this->mMapName;
if((theMapName == "") && !inLocalOnly )
{
const char* theLevelName = gEngfuncs.pfnGetLevelName();
if(theLevelName)
{
theMapName = string(theLevelName);
// Remove maps/ from the beginning and .bsp from the end.
StringVector theVector;
Tokenizer::split(theMapName, "/.", theVector);
if(theVector.size() >= 2)
{
theMapName = theVector[1];
}
}
}
return theMapName;
}
int AvHHud::GetNumActiveHives() const
{
int theNumActiveHives = 0;
if(this->GetIsAlien())
{
for(HiveInfoListType::const_iterator theIter = this->mHiveInfoList.begin(); theIter != this->mHiveInfoList.end(); theIter++)
{
if(theIter->mStatus == kHiveInfoStatusBuilt)
{
theNumActiveHives++;
}
}
}
return theNumActiveHives;
}
int AvHHud::GetMaxAlienResources() const
{
int theMaxAlienResources = kMaxAlienResources;
if(this->mMaxResources >= 0)
{
theMaxAlienResources = this->mMaxResources;
}
return theMaxAlienResources;
}
bool AvHHud::SetGamma(float inSlope)
{
bool theSuccess = false;
// Disable gamma stuff in debug for sanity
// #ifndef DEBUG
HDC theDC = GetDC(NULL);
if(theDC != 0)
{
const float kGammaIncrement = 0.05f;
float theGammaToTry = inSlope + kGammaIncrement;
while(!theSuccess && (theGammaToTry > 1.0f))
{
theGammaToTry -= kGammaIncrement;
sGameGammaTable.ProcessSlope(theGammaToTry);
// tankefugl: fakes a successful gamma ramp change if cl_gammaramp is set to 0
if((CVAR_GET_FLOAT(kvGammaRamp) == 0) || sGameGammaTable.InitializeToVideoState())
{
// Tell UI components so they can change shading to look the same
this->GetManager().NotifyGammaChange(theGammaToTry);
// aww yeah
theSuccess = true;
}
}
char theMessage[256];
if(theSuccess)
{
sprintf(theMessage, "Gamma set to %f.", theGammaToTry);
}
else
{
sprintf(theMessage, "Display doesn't support downloadable gamma ramps.");
}
if(!theSuccess || (gEngfuncs.GetMaxClients() == 1))
{
CenterPrint(theMessage);
}
if(!ReleaseDC(NULL, theDC))
{
// emit error about leak
}
}
//#endif
return theSuccess;
}
bool AvHHud::SlotInput(int inSlot)
{
bool theHandled = false;
if(this->mInTopDownMode)
{
if((inSlot >= 0) && (inSlot < kNumHotkeyGroups))
{
// TODO: Read state of control/duck here
bool theCreateGroup = false;
int theButtonBits = CL_ButtonBits(0);
if(theButtonBits & IN_DUCK)
{
theCreateGroup = true;
}
int theBaseOffset = theCreateGroup ? GROUP_CREATE_1 : GROUP_SELECT_1;
this->mGroupEvent = (AvHMessageID)(theBaseOffset + inSlot);
theHandled = true;
}
}
return theHandled;
}
int AvHHud::Redraw( float flTime, int intermission )
{
if (!gViewPort->IsOptionsMenuVisible() &&
!gParticleEditorHandler.GetInEditMode())
{
Render();
}
int theRC = UIHud::Redraw(flTime, intermission);
return theRC;
}
void AvHHud::ResetGammaAtExit()
{
sPregameGammaTable.InitializeToVideoState();
}
int AvHHud::ResetGammaAtExitForOnExit()
{
sPregameGammaTable.InitializeToVideoState();
return TRUE;
}
void AvHHud::ResetGammaAtExit(int inSig)
{
AvHHud::ResetGammaAtExit();
}
void AvHHud::ResetTopDownUI()
{
this->mGhostBuilding = MESSAGE_NULL;
this->mSelected.clear();
this->mSelectionEffects.clear();
gCommanderHandler.Reset();
for(int i = 0; i < kNumHotkeyGroups; i++)
{
this->mGroups[i].clear();
this->mGroupTypes[i] = AVH_USER3_NONE;
this->mGroupAlerts[i] = ALERT_NONE;
}
this->mSelectAllGroup.clear();
}
void AvHHud::SetSelectingWeaponID(int inWeaponID, int inR, int inG, int inB)
{
if(gEngfuncs.pfnGetCvarFloat(kvAutoHelp))
{
if(inR != -1)
{
this->mHelpMessage.SetR(inR);
}
if(inG != -1)
{
this->mHelpMessage.SetG(inG);
}
if(inB != -1)
{
this->mHelpMessage.SetB(inB);
}
this->mSelectingWeaponID = inWeaponID;
}
}
void AvHHud::SetTechHelpText(const string& inTechHelpText)
{
this->mTechHelpText = inTechHelpText;
}
BIND_MESSAGE(Countdown);
int AvHHud::Countdown(const char* pszName, int iSize, void* pbuf)
{
NetMsg_UpdateCountdown( pbuf, iSize, this->mNumTicksToPlay );
this->mLastTickPlayed = 1;
this->mCountDownClock = this->m_flTime;
return 1;
}
bool AvHHud::GetAmbientSoundNameFromIndex(string& outSoundName, int inSoundIndex) const
{
bool theFoundName = false;
if(inSoundIndex < (int)(this->mSoundNameList.size()))
{
outSoundName = this->mSoundNameList[inSoundIndex];
theFoundName = true;
}
return theFoundName;
}
void AvHHud::ModifyAmbientSoundEntryIfChanged(bool inSoundOn, int inSoundIndex, int inEntIndex, float inTimeStarted, int inVolume, int inFadeDistance, int inFlags, Vector inOrigin)
{
bool theFoundSound = false;
// Look up sound using inSoundIndex
string theSoundName;
if(this->GetAmbientSoundNameFromIndex(theSoundName, inSoundIndex))
{
// Loop through current sounds
for(AmbientSoundListType::iterator theIter = this->mAmbientSounds.begin(); theIter != this->mAmbientSounds.end(); )
{
bool theErasedSound = false;
if(theIter->GetEntityIndex() == inEntIndex)
{
// If found, remember that we found it
theFoundSound = true;
// Set position
theIter->SetPosition(inOrigin);
// If we're turning off sound, kill the sound
if(!inSoundOn)
{
theIter->ClearData();
theIter = this->mAmbientSounds.erase(theIter);
theErasedSound = true;
}
}
if(!theErasedSound)
{
theIter++;
}
}
// If we're turning a sound on, and we didn't find one
if(inSoundOn && !theFoundSound)
{
bool theLooping = inFlags & 2;
float theTimeElapsed = this->mTimeOfLastUpdate - inTimeStarted;
// Add new entry with these values
this->mAmbientSounds.push_back(AvHAmbientSound(theSoundName, inVolume, inFadeDistance, theLooping, inOrigin, inEntIndex, theTimeElapsed));
}
}
else
{
// We may not have the sound list yet, it's OK
//ASSERT(false);
}
}
// tankefugl:
void AvHHud::SetCenterText(const char* inText)
{
LocalizeString(inText, this->mCenterText);
this->mCenterTextTime = this->mTimeOfLastUpdate;
}
void AvHHud::ClearCenterText()
{
this->mCenterText.clear();
this->mCenterTextTime = -1;
}
// :tankefugl
// Look at incoming order. If we are one of the receivers, play a HUD sound
// indicating our new order
void AvHHud::OrderNotification(const AvHOrder& inOrder)
{
//if(!inOrder.GetOrderCompleted())
//{
// If we are commander, or we are in receiver list
int theLocalPlayer = gEngfuncs.GetLocalPlayer()->index;
if((this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER) || (inOrder.GetHasReceiver(theLocalPlayer)))
{
// Do a switch on the order type
AvHOrderType theOrderType = inOrder.GetOrderType();
AvHHUDSound theSound = HUD_SOUND_INVALID;
// tankefugl: 0000992
// popup indicator for order
bool thePopup = false;
// Play HUD sound depending on order
switch(theOrderType)
{
case ORDERTYPEL_MOVE:
theSound = HUD_SOUND_ORDER_MOVE;
thePopup = true;
break;
case ORDERTYPET_ATTACK:
theSound = HUD_SOUND_ORDER_ATTACK;
thePopup = true;
break;
case ORDERTYPET_BUILD:
theSound = HUD_SOUND_ORDER_BUILD;
thePopup = true;
break;
case ORDERTYPET_GUARD:
theSound = HUD_SOUND_ORDER_GUARD;
thePopup = true;
break;
case ORDERTYPET_WELD:
theSound = HUD_SOUND_ORDER_WELD;
thePopup = true;
break;
case ORDERTYPET_GET:
theSound = HUD_SOUND_ORDER_GET;
thePopup = true;
break;
}
if((this->GetHUDUser3() == AVH_USER3_MARINE_PLAYER) && (inOrder.GetOrderCompleted()))
{
theSound = HUD_SOUND_ORDER_COMPLETE;
}
this->PlayHUDSound(theSound);
// tankefugl: 0000992 | 0001052
if (thePopup && (this->GetInTopDownMode() == false) && (inOrder.GetOrderActive()))
{
this->SetDisplayOrder(2, this->GetFrameForOrderType(theOrderType), "", "", "");
}
// :tankefugl
}
//}
}
void AvHHud::ResetComponentsForUser3()
{
this->mPieMenuControl = "";
this->GetManager().HideComponents();
if(gParticleEditorHandler.GetInEditMode())
{
gHUD.GetManager().UnhideComponent(kPSESizeSlider);
gHUD.GetManager().UnhideComponent(kPSESizeLabel);
gHUD.GetManager().UnhideComponent(kPSEScaleSlider);
gHUD.GetManager().UnhideComponent(kPSEScaleLabel);
gHUD.GetManager().UnhideComponent(kPSEGenerationRateSlider);
gHUD.GetManager().UnhideComponent(kPSEGenerationRateLabel);
gHUD.GetManager().UnhideComponent(kPSEParticleLifetimeSlider);
gHUD.GetManager().UnhideComponent(kPSEParticleLifetimeLabel);
gHUD.GetManager().UnhideComponent(kPSEParticleSystemLifetimeSlider);
gHUD.GetManager().UnhideComponent(kPSEParticleSystemLifetimeLabel);
gHUD.GetManager().UnhideComponent(kPSEMaxParticlesSlider);
gHUD.GetManager().UnhideComponent(kPSEMaxParticlesLabel);
gHUD.GetManager().UnhideComponent(kPSEDrawModeSlider);
gHUD.GetManager().UnhideComponent(kPSEDrawModeLabel);
gHUD.GetManager().UnhideComponent(PSEGenVelToggleSlider);
gHUD.GetManager().UnhideComponent(kPSEGenVelToggleLabel);
gHUD.GetManager().UnhideComponent(kPSEGenVelShapeSlider);
gHUD.GetManager().UnhideComponent(kPSEGenVelShapeLabel);
gHUD.GetManager().UnhideComponent(kPSEGenVelParamNumSlider);
gHUD.GetManager().UnhideComponent(kPSEGenVelParamNumLabel);
gHUD.GetManager().UnhideComponent(kPSEGenVelParamValueSlider);
gHUD.GetManager().UnhideComponent(kPSEGenVelParamValueLabel);
}
else
{
bool theIsCombatMode = (this->mMapMode == MAP_MODE_CO);
bool theIsNSMode = (this->mMapMode == MAP_MODE_NS);
if((this->GetHUDPlayMode() == PLAYMODE_PLAYING) && !this->GetIsNotInControl() && !gViewPort->IsOptionsMenuVisible())
{
switch(this->GetHUDUser3())
{
case AVH_USER3_MARINE_PLAYER:
if(theIsCombatMode)
{
this->mPieMenuControl = kSoldierCombatMenu;
}
else if(theIsNSMode)
{
this->mPieMenuControl = kSoldierMenu;
}
if (g_iUser1 == OBS_NONE)
{
this->GetManager().UnhideComponent(mPieMenuControl.c_str());
}
// Removed these for recording footage until they look better
//this->GetManager().UnhideComponent(kReinforcementsLabel);
//this->GetManager().UnhideComponent(kResourceLabel);
//this->GetManager().UnhideComponent(kMouseCursorLabel);
//this->GetManager().UnhideComponent(kDebugCSPServerLabel);
//this->GetManager().UnhideComponent(kDebugCSPClientLabel);
break;
case AVH_USER3_COMMANDER_PLAYER:
if(this->mInTopDownMode)
{
this->GetManager().UnhideComponent(kSelectionBox);
this->GetManager().UnhideComponent(kCommanderResourceLabel);
//this->GetManager().UnhideComponent(kMouseCursorLabel);
this->GetManager().UnhideComponent(kLeaveCommanderButton);
this->GetManager().UnhideComponent(kScroller);
this->GetManager().UnhideComponent(kTechHelpText);
this->GetManager().UnhideComponent(kHierarchy);
this->GetManager().UnhideComponent(kResearchBackgroundPanel);
this->GetManager().UnhideComponent(kActionButtonsComponents);
this->GetManager().UnhideComponent(kSelectAllImpulsePanel);
//this->GetManager().UnhideComponent(kTopDownHUDTopSpritePanel);
//this->GetManager().UnhideComponent(kTopDownHUDBottomSpritePanel);
}
//this->GetManager().UnhideComponent(kReinforcementsLabel);
break;
case AVH_USER3_ALIEN_PLAYER1:
case AVH_USER3_ALIEN_PLAYER2:
case AVH_USER3_ALIEN_PLAYER3:
case AVH_USER3_ALIEN_PLAYER4:
case AVH_USER3_ALIEN_PLAYER5:
if(theIsCombatMode)
{
this->mPieMenuControl = kAlienCombatMenu;
}
else if(theIsNSMode)
{
this->mPieMenuControl = kAlienMenu;
}
if (g_iUser1 == OBS_NONE)
{
this->GetManager().UnhideComponent(mPieMenuControl.c_str());
}
//this->GetManager().UnhideComponent(kMouseCursorLabel);
//this->GetManager().UnhideComponent(kDebugCSPServerLabel);
//this->GetManager().UnhideComponent(kDebugCSPClientLabel);
break;
case AVH_USER3_ALIEN_EMBRYO:
//this->GetManager().UnhideComponent(kAlienMembrane);
break;
}
if(sShowMap)
{
this->GetManager().UnhideComponent(kShowMapHierarchy);
}
mOverviewMap.SetUser3(this->GetHUDUser3());
// Update command hierarchy so it can potentially display differently
if(this->mHierarchy)
{
this->mHierarchy->setPos(.0105f*ScreenWidth(), .728*ScreenHeight());
this->mHierarchy->setSize(.265*ScreenWidth(), .247*ScreenHeight());
}
}
}
}
BIND_MESSAGE(BalanceVar);
int AvHHud::BalanceVar(const char* pszName, int iSize, void* pbuf)
{
string name;
BalanceMessageAction action;
int ivalue;
float fvalue;
string svalue;
NetMsg_BalanceVar( pbuf, iSize, name, action, ivalue, fvalue, svalue );
BalanceValueContainer* container = BalanceValueContainerFactory::get();
switch( action )
{
case BALANCE_ACTION_INSERT_INT:
container->insert(name,ivalue);
break;
case BALANCE_ACTION_INSERT_FLOAT:
container->insert(name,fvalue);
break;
case BALANCE_ACTION_INSERT_STRING:
container->insert(name,svalue);
break;
case BALANCE_ACTION_REMOVE:
container->remove(name);
break;
case BALANCE_ACTION_CLEAR:
container->clear();
break;
}
return 1;
}
BIND_MESSAGE(GameStatus);
int AvHHud::GameStatus(const char* pszName, int iSize, void* pbuf)
{
int status, game_time, timelimit, misc_data;
AvHMapMode map_mode;
NetMsg_GameStatus( pbuf, iSize, status, map_mode, game_time, timelimit, misc_data );
this->mMapMode = map_mode;
switch( status )
{
case kGameStatusReset:
case kGameStatusResetNewMap:
if(this->mInTopDownMode)
{
this->ToggleMouse();
}
this->ResetGame( status == kGameStatusResetNewMap ? true : false );
break;
case kGameStatusEnded: // Victor determined, but we are still in the cooldown time
this->mGameEnded = true; // Stop research
break;
case kGameStatusGameTime:
this->mGameTime = game_time;
this->mTimeLimit = timelimit;
this->mCombatAttackingTeamNumber = misc_data;
break;
case kGameStatusUnspentLevels:
this->mExperienceLevelSpent = misc_data;
break;
}
return 1;
}
BIND_MESSAGE(MiniMap);
int AvHHud::MiniMap(const char* pszName, int iSize, void* pbuf)
{
gMiniMap.ReceiveFromNetworkStream( pbuf, iSize );
return 1;
}
// tankefugl: 0000971
BIND_MESSAGE(IssueOrder);
int AvHHud::IssueOrder(const char* pszName, int iSize, void* pbuf)
{
int ordertype, ordersource, ordertarget;
NetMsg_IssueOrder( pbuf, iSize, ordertype, ordersource, ordertarget);
float now = this->GetTimeOfLastUpdate();
TeammateOrderListType::iterator theIter = this->mTeammateOrder.find(ordersource);
if (theIter == this->mTeammateOrder.end())
{
this->mTeammateOrder.insert(theIter, pair<int, TeammateOrderType>(ordersource, TeammateOrderType(ordertype, now)));
}
else
{
TeammateOrderType *theOrder = &((*theIter).second);
(*theOrder).first = ordertype;
(*theOrder).second = now;
}
if (this->GetInTopDownMode() == false)
{
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
if (theLocalPlayer->index == ordertarget)
{
hud_player_info_t info;
memset(&info, 0, sizeof(info));
GetPlayerInfo(ordersource, &info);
string temp;
string nameFormat;
// fetch from titles.txt
sprintf(temp, "TeammateOrder%d", ordertype);
LocalizeString(temp.c_str(), nameFormat);
sprintf(temp, nameFormat.c_str(), info.name);
this->SetDisplayOrder(1, ordertype, temp, "", "");
}
if (theLocalPlayer->index == ordersource)
{
this->mCurrentOrderTarget = ordertarget;
this->mCurrentOrderType = ordertype;
this->mCurrentOrderTime = now;
}
}
return 1;
}
// :tankefugl
BIND_MESSAGE(ServerVar);
int AvHHud::ServerVar(const char* pszName, int iSize, void* pbuf)
{
string name, value;
NetMsg_ServerVar( pbuf, iSize, name, value );
mServerVariableMap[name] = value;
return 1;
}
BIND_MESSAGE(Progress);
int AvHHud::Progress(const char* pszName, int iSize, void* pbuf)
{
NetMsg_ProgressBar( pbuf, iSize, this->mProgressBarEntityIndex, this->mProgressBarParam );
return 1;
}
// Start the game over. Called after the game ends and also after a map change
void AvHHud::ResetGame(bool inMapChanged)
{
UIHud::ResetGame();
this->mResources = 0;
this->mMaxResources = -1;
this->mVisualResources = 0;
this->mUser2OfLastResourceMessage = 0;
this->mTimeOfLastEntityUpdate = -1;
this->mVisualEnergyLevel = 0;
this->mUser2OfLastEnergyLevel = 0;
// Don't use a menu yet
//this->ResetUpgradeCosts();
// Reset armor as well.
//this->mArmorLevel = ARMOR_BASE;
// Clear out all particle systems and templates
if(inMapChanged)
{
gParticleTemplateList.Clear();
this->mTimeOfLastUpdate = 0.0f;
this->mInfoLocationList.clear();
}
// puzl: 1066 reset overview map on game restart
gHUD.GetOverviewMap().Clear();
AvHParticleSystemManager::Instance()->Reset();
this->mTechSlotManager.Clear();
this->mTechNodes.Clear();
this->mTimeOfCurrentUpdate = 0.0f;
// On game reset, clear blips (happens on server as well)
this->mEntityHierarchy.Clear();
// Clear selection effects
this->mSelectionEffects.clear();
// End any jetpack effects
//EndJetpackEffects();
// Clear client scripts
AvHScriptManager::Instance()->Reset();
// Selection and commander variables
this->mNumLocalSelectEvents = 0;
this->mMapMode = MAP_MODE_UNDEFINED;
this->mInTopDownMode = false;
this->mLeftMouseStarted = false;
this->mLeftMouseEnded = false;
this->mPlacingBuilding = false;
sShowMap = false;
this->StopMusic();
for(AmbientSoundListType::iterator theIter = this->mAmbientSounds.begin(); theIter != this->mAmbientSounds.end(); theIter++)
{
theIter->ClearData();
}
this->mAmbientSounds.clear();
this->SetReinforcements(0);
this->mOrders.clear();
this->mCurrentCursorFrame = 0;
this->mProgressBarEntityIndex = -1;
this->mProgressBarParam = -1;
this->mEnemyBlips.Clear();
this->mFriendlyBlips.Clear();
// Reset view angles (in case player was in commander mode)
gViewAngles.z = 0.0f;
gResetViewAngles = true;
// Clear location
this->mLocationText = "";
this->mUpgrades.clear();
this->mNumUpgradesAvailable = 0;
int i;
for(i = 0; i < ALIEN_UPGRADE_CATEGORY_MAX_PLUS_ONE; i++)
{
this->mCurrentUpgradeCategory[i] = ALIEN_UPGRADE_CATEGORY_INVALID;
}
// Remove all decals (no idea how to get the total decals)
//for(i = 0; i < 1024; i++)
//{
// gEngfuncs.pEfxAPI->R_DecalRemoveAll(i);
//}
RemoveAllDecals();
// Remove temp ghost building
if(this->mLastGhostBuilding)
{
this->mLastGhostBuilding->die = -1;
}
this->mNumericalInfoEffects.clear();
this->mTimeOfNextHudSound = -1;
this->mLastHUDSoundPlayed = HUD_SOUND_INVALID;
//this->mTooltips.clear();
this->mHiveInfoList.clear();
this->mDesiredGammaSlope = kDefaultMapGamma;
this->mRecordingLastFrame = false;
this->mTimeOfLastHelpText = -1;
this->mDisplayedToolTipList.clear();
this->mCurrentWeaponID = -1;
this->mCurrentWeaponEnabled = false;
// Is this needed?
//this->mCurrentUIMode = MAIN_MODE;
this->mMenuTechSlots = 0;
this->mPendingRequests.clear();
for(i = 0; i < kNumHotkeyGroups; i++)
{
this->mGroups[i].clear();
this->mGroupTypes[i] = AVH_USER3_NONE;
this->mGroupAlerts[i] = ALERT_NONE;
}
this->mSelectAllGroup.clear();
this->mCurrentSquad = 0;
this->mBlinkingAlertType = 0;
this->mLastTeamSpectated = TEAM_IND;
this->mStructureNotificationList.clear();
this->mGameTime = -1;
this->mTimeLimit = -1;
this->mCombatAttackingTeamNumber = 0;
this->mGameEnded = false;
this->mExperience = 0;
this->mExperienceLevel = 1;
this->mExperienceLevelLastDrawn = 1;
this->mExperienceLevelSpent = 0;
this->mTimeOfLastLevelUp = -1;
memset(this->mMenuImpulses, MESSAGE_NULL, sizeof(AvHMessageID)*kNumUpgradeLines);
// tankefugl: 0000992 & 0000971
this->mTeammateOrder.clear();
this->mCurrentOrderTarget = 0;
this->mCurrentOrderType = 0;
this->mCurrentOrderTime = 0.0f;
this->mDisplayOrderTime = 0.0f;
this->mDisplayOrderType = 0;
this->mDisplayOrderIndex = 0;
this->mDisplayOrderText1 = "";
this->mDisplayOrderText2 = "";
this->mDisplayOrderText3 = "";
this->mCenterText.clear();
this->mCenterTextTime = -1;
// :tankefugl
}
BIND_MESSAGE(SetGmma);
int AvHHud::SetGmma(const char* pszName, int iSize, void* pbuf)
{
NetMsg_SetGammaRamp( pbuf, iSize, this->mDesiredGammaSlope );
if (!mSteamUIActive)
{
this->SetGamma(this->mDesiredGammaSlope);
}
return 1;
}
BIND_MESSAGE(BlipList);
int AvHHud::BlipList(const char* pszName, int iSize, void* pbuf)
{
bool friendly_blips;
AvHVisibleBlipList list;
NetMsg_BlipList( pbuf, iSize, friendly_blips, list );
float theCurrentTime = gEngfuncs.GetClientTime();
if( friendly_blips )
{
this->mFriendlyBlips.Clear();
this->mFriendlyBlips.AddBlipList(list);
this->mFriendlyBlips.SetTimeBlipsReceived(theCurrentTime);
}
else
{
this->mEnemyBlips.Clear();
this->mEnemyBlips.AddBlipList(list);
this->mEnemyBlips.SetTimeBlipsReceived(theCurrentTime);
}
return 1;
}
BIND_MESSAGE(ClScript);
int AvHHud::ClScript(const char *pszName, int iSize, void *pbuf)
{
StringList script_names;
NetMsg_ClientScripts( pbuf, iSize, script_names );
StringList::iterator current, end = script_names.end();
for( current = script_names.begin(); current != end; ++current )
{
AvHScriptManager::Instance()->RunScript(current->c_str());
}
return 1;
}
BIND_MESSAGE(Particles);
int AvHHud::Particles(const char *pszName, int iSize, void *pbuf)
{
AvHParticleTemplate particle_template;
NetMsg_SetParticleTemplate( pbuf, iSize, particle_template );
gParticleTemplateList.Insert( particle_template );
return 1;
}
BIND_MESSAGE(SoundNames);
int AvHHud::SoundNames(const char *pszName, int iSize, void *pbuf)
{
bool theClearSoundList;
string sound_name;
NetMsg_SetSoundNames( pbuf, iSize, theClearSoundList, sound_name );
if(theClearSoundList)
{
this->mSoundNameList.clear();
}
else
{
this->mSoundNameList.push_back(sound_name);
}
return 1;
}
BIND_MESSAGE(SetSelect);
int AvHHud::SetSelect(const char* pszName, int iSize, void* pbuf)
{
Selection selection;
NetMsg_SetSelect( pbuf, iSize, selection );
EntityListType theGroup;
switch( selection.group_number )
{
case 0:
this->mTrackingEntity = selection.tracking_entity;
if( selection.selected_entities != this->mSelected )
{
this->mSelectionJustChanged = true;
this->mSelected = selection.selected_entities;
}
break;
case kSelectAllHotGroup:
this->mSelectAllGroup = selection.selected_entities;
break;
default:
this->mGroups[selection.group_number-1] = selection.selected_entities;
this->mGroupTypes[selection.group_number-1] = selection.group_type;
this->mGroupAlerts[selection.group_number-1] = selection.group_alert;
}
return 1;
}
BIND_MESSAGE(SetRequest);
int AvHHud::SetRequest(const char* pszName, int iSize, void* pbuf)
{
int request_type, request_count;
NetMsg_SetRequest( pbuf, iSize, request_type, request_count );
this->mPendingRequests[(AvHMessageID)request_type] = request_count;
return 1;
}
BIND_MESSAGE(SetOrder);
int AvHHud::SetOrder(const char* pszName, int iSize, void* pbuf)
{
AvHOrder theNewOrder;
NetMsg_SetOrder( pbuf, iSize, theNewOrder );
AvHChangeOrder(this->mOrders, theNewOrder);
// Give feedback on order
this->OrderNotification(theNewOrder);
// Run through orders, deleting any that are complete
for(OrderListType::iterator theIter = this->mOrders.begin(); theIter != this->mOrders.end(); /* no inc */)
{
if(theIter->GetOrderCompleted())
{
this->mOrders.erase(theIter);
}
else
{
theIter++;
}
}
return 1;
}
BIND_MESSAGE(SetupMap);
int AvHHud::SetupMap(const char* pszName, int iSize, void* pbuf)
{
bool is_location, draw_background;
float min_extents[3], max_extents[3];
string name;
NetMsg_SetupMap( pbuf, iSize, is_location, name, min_extents, max_extents, draw_background );
if( is_location )
{
vec3_t theMaxExtent;
theMaxExtent.x = max_extents[0];
theMaxExtent.y = max_extents[1];
theMaxExtent.z = max_extents[2];
vec3_t theMinExtent;
theMinExtent.x = min_extents[0];
theMinExtent.y = min_extents[1];
theMinExtent.z = min_extents[2];
this->mInfoLocationList.push_back( AvHBaseInfoLocation( name, theMaxExtent, theMinExtent ) );
}
else
{
this->mMapName = name;
this->mMapExtents.SetMaxMapX( max_extents[0] );
this->mMapExtents.SetMaxMapY( max_extents[1] );
this->mMapExtents.SetMaxViewHeight( max_extents[2] );
this->mMapExtents.SetMinMapX( min_extents[0] );
this->mMapExtents.SetMinMapY( min_extents[1] );
this->mMapExtents.SetMinViewHeight( min_extents[2] );
this->mMapExtents.SetDrawMapBG( draw_background );
}
return 1;
}
BIND_MESSAGE(SetTopDown);
int AvHHud::SetTopDown(const char* pszName, int iSize, void* pbuf)
{
bool is_menu_tech, is_top_down;
float position[3];
int tech_slots;
NetMsg_SetTopDown( pbuf, iSize, is_menu_tech, is_top_down, position, tech_slots );
if(is_menu_tech)
{
this->mMenuTechSlots = tech_slots;
}
else
{
if(this->mInTopDownMode && !is_top_down)
{
// Switch away from top down mode
this->mInTopDownMode = false;
this->ToggleMouse();
// Reset angles
gViewAngles[0] = position[0];
gViewAngles[1] = position[1];
gViewAngles[2] = position[2];
gResetViewAngles = true;
this->mSelectionEffects.clear();
}
else if(!this->mInTopDownMode && is_top_down)
{
// Switch to top down mode!
this->mInTopDownMode = true;
this->ToggleMouse();
}
if(is_top_down)
{
// Read new PAS
this->mCommanderPAS.x = position[0];
this->mCommanderPAS.y = position[1];
this->mCommanderPAS.z = position[2];
}
}
return 1;
}
BIND_MESSAGE(EntHier);
int AvHHud::EntHier(const char *pszName, int iSize, void *pbuf)
{
MapEntityMap new_items;
EntityListType old_items;
NetMsg_UpdateEntityHierarchy( pbuf, iSize, new_items, old_items );
MapEntityMap::iterator current, end = new_items.end();
for( current = new_items.begin(); current != end; ++current )
{
this->mEntityHierarchy.InsertEntity( current->first, current->second );
}
EntityListType::iterator d_current, d_end = old_items.end();
for( d_current = old_items.begin(); d_current != d_end; ++d_current )
{
this->mEntityHierarchy.DeleteEntity( *d_current );
}
return 0;
}
BIND_MESSAGE(EditPS);
int AvHHud::EditPS(const char* pszName, int iSize, void* pbuf)
{
int particle_index;
NetMsg_EditPS( pbuf, iSize, particle_index );
AvHParticleEditorHandler::SetEditIndex((uint32)particle_index);
return 1;
}
BIND_MESSAGE(Fog);
int AvHHud::Fog(const char* pszName, int iSize, void* pbuf)
{
bool enabled;
int R, G, B;
float start, end;
NetMsg_Fog( pbuf, iSize, enabled, R, G, B, start, end );
this->mFogActive = enabled;
if(enabled)
{
this->mFogColor.x = R;
this->mFogColor.y = G;
this->mFogColor.z = B;
this->mFogStart = start;
this->mFogEnd = end;
}
return 1;
}
BIND_MESSAGE(ListPS);
int AvHHud::ListPS(const char* pszName, int iSize, void* pbuf)
{
string name;
NetMsg_ListPS( pbuf, iSize, name );
this->m_SayText.SayTextPrint(name.c_str(), 256, 0);
return 1;
}
BIND_MESSAGE(PlayHUDNot);
int AvHHud::PlayHUDNot(const char* pszName, int iSize, void* pbuf)
{
int message_id, sound;
float location_x, location_y;
NetMsg_PlayHUDNotification( pbuf, iSize, message_id, sound, location_x, location_y );
if(message_id == 0)
{
// Hack to avoid adding another network message (at max)
if(!this->GetInTopDownMode())
{
switch(sound)
{
case HUD_SOUND_SQUAD1:
this->mCurrentSquad = 1;
break;
case HUD_SOUND_SQUAD2:
this->mCurrentSquad = 2;
break;
case HUD_SOUND_SQUAD3:
this->mCurrentSquad = 3;
break;
case HUD_SOUND_SQUAD4:
this->mCurrentSquad = 4;
break;
case HUD_SOUND_SQUAD5:
this->mCurrentSquad = 5;
break;
}
}
else
{
switch((AvHHUDSound)sound)
{
// Danger
case HUD_SOUND_MARINE_SOLDIER_UNDER_ATTACK:
case HUD_SOUND_MARINE_BASE_UNDER_ATTACK:
case HUD_SOUND_MARINE_SENTRYDAMAGED:
case HUD_SOUND_MARINE_SOLDIERLOST:
case HUD_SOUND_MARINE_CCUNDERATTACK:
this->mBlinkingAlertType = 2;
AddMiniMapAlert(location_x, location_y);
break;
// Just research or something like that
case HUD_SOUND_MARINE_UPGRADE_COMPLETE:
case HUD_SOUND_MARINE_RESEARCHCOMPLETE:
this->mBlinkingAlertType = 1;
AddMiniMapAlert(location_x, location_y);
break;
}
}
this->PlayHUDSound((AvHHUDSound)sound);
}
else
{
// Push back icon
HUDNotificationType theNotification;
theNotification.mStructureID = (AvHMessageID)sound; //message_id;
theNotification.mTime = this->mTimeOfCurrentUpdate;
theNotification.mLocation = Vector(location_x, location_y, 0.0f);
if(CVAR_GET_FLOAT(kvBuildMessages))
{
this->mStructureNotificationList.push_back(theNotification);
}
}
return 1;
}
BIND_MESSAGE(AlienInfo);
int AvHHud::AlienInfo(const char* pszName, int iSize, void* pbuf)
{
bool was_hive_info;
AvHAlienUpgradeListType upgrades;
HiveInfoListType hives;
NetMsg_AlienInfo( pbuf, iSize, was_hive_info, this->mUpgrades, this->mHiveInfoList );
return 1;
}
void AvHHud::PlayHUDSound(const char *szSound, float vol, float inSoundLength)
{
if((this->mTimeOfNextHudSound == -1) || (this->mTimeOfCurrentUpdate > this->mTimeOfNextHudSound))
{
if(szSound)
{
char theSoundName[512];
strcpy(theSoundName, szSound);
gEngfuncs.pfnPlaySoundByName(theSoundName, vol);
this->mTimeOfNextHudSound = this->mTimeOfCurrentUpdate + inSoundLength;
}
}
}
void AvHHud::PlayHUDSound(int iSound, float vol, float inSoundLength)
{
if((this->mTimeOfNextHudSound == -1) || (this->mTimeOfCurrentUpdate > this->mTimeOfNextHudSound))
{
gEngfuncs.pfnPlaySoundByIndex(iSound, vol);
this->mTimeOfNextHudSound = this->mTimeOfCurrentUpdate + inSoundLength;
}
}
void AvHHud::PlayHUDSound(AvHHUDSound inSound)
{
char* theSoundPtr = NULL;
float theVolume = 1.0f;
// Some sounds are forced, but don't allow them to be spammed or cut themselves off
bool theForceSound = AvHSHUGetForceHUDSound(inSound) && (inSound != this->mLastHUDSoundPlayed);
// tankefugl: 0000407
bool theAutoHelpEnabled = gEngfuncs.pfnGetCvarFloat(kvAutoHelp);
// :tankefugl
if((this->mTimeOfNextHudSound == -1) || (this->mTimeOfCurrentUpdate >= this->mTimeOfNextHudSound) || theForceSound)
{
float theSoundLength = 2.0f;
switch(inSound)
{
case HUD_SOUND_POINTS_SPENT:
theSoundPtr = kPointsSpentSound;
theSoundLength = .2f;
break;
case HUD_SOUND_COUNTDOWN:
theSoundPtr = kCountdownSound;
theSoundLength = 0.0f;
break;
case HUD_SOUND_SELECT:
if(gHUD.GetIsAlien())
theSoundPtr = kSelectAlienSound;
else
theSoundPtr = kSelectSound;
// Set to 0 so it never blocks other sounds
theVolume = .2f;
theSoundLength = 0.0f;
break;
case HUD_SOUND_SQUAD1:
if(this->GetInTopDownMode())
{
theSoundPtr = kSquad1Sound;
theSoundLength = 1.2f;
}
else
{
theSoundPtr = kMarineSquad1Sound;
theSoundLength = 2.0f;
}
break;
case HUD_SOUND_SQUAD2:
if(this->GetInTopDownMode())
{
theSoundPtr = kSquad2Sound;
theSoundLength = 1.2f;
}
else
{
theSoundPtr = kMarineSquad2Sound;
theSoundLength = 2.0f;
}
break;
case HUD_SOUND_SQUAD3:
if(this->GetInTopDownMode())
{
theSoundPtr = kSquad3Sound;
theSoundLength = 1.2f;
}
else
{
theSoundPtr = kMarineSquad3Sound;
theSoundLength = 2.0f;
}
break;
case HUD_SOUND_SQUAD4:
if(this->GetInTopDownMode())
{
theSoundPtr = kSquad4Sound;
theSoundLength = 1.2f;
}
else
{
theSoundPtr = kMarineSquad4Sound;
theSoundLength = 2.0f;
}
break;
case HUD_SOUND_SQUAD5:
if(this->GetInTopDownMode())
{
theSoundPtr = kSquad5Sound;
theSoundLength = 1.2f;
}
else
{
theSoundPtr = kMarineSquad5Sound;
theSoundLength = 2.0f;
}
break;
case HUD_SOUND_PLACE_BUILDING:
theSoundPtr = kPlaceBuildingSound;
theSoundLength = .2f;
break;
case HUD_SOUND_MARINE_POINTS_RECEIVED:
theSoundPtr = kMarinePointsReceivedSound;
theSoundLength = 1.42f;
break;
case HUD_SOUND_MARINE_RESEARCHCOMPLETE:
theSoundPtr = kMarineResearchComplete;
theSoundLength = 2.0f;
break;
case HUD_SOUND_MARINE_SOLDIER_UNDER_ATTACK:
theSoundPtr = kMarineSoldierUnderAttack;
theSoundLength = 3.0f;
break;
case HUD_SOUND_MARINE_CCONLINE:
if(rand() % 2)
{
theSoundPtr = kMarineCCOnline1;
}
else
{
theSoundPtr = kMarineCCOnline2;
}
theSoundLength = 2.3f;
break;
case HUD_SOUND_MARINE_CCUNDERATTACK:
if(rand() % 2)
{
theSoundPtr = kMarineCCUnderAttack1;
}
else
{
theSoundPtr = kMarineCCUnderAttack2;
}
theSoundLength = 3.0f;
break;
case HUD_SOUND_MARINE_COMMANDER_EJECTED:
theSoundPtr = kMarineCommanderEjected;
theSoundLength = 3.0f;
break;
case HUD_SOUND_MARINE_BASE_UNDER_ATTACK:
if(rand() % 2)
{
theSoundPtr = kMarineBaseUnderAttack1;
}
else
{
theSoundPtr = kMarineBaseUnderAttack2;
}
theSoundLength = 3.0f;
break;
case HUD_SOUND_MARINE_UPGRADE_COMPLETE:
theSoundPtr = kMarineUpgradeComplete;
theSoundLength = 1.0f;
break;
case HUD_SOUND_MARINE_MORE:
theSoundPtr = kMarineMoreResources;
theSoundLength = 1.8f;
break;
case HUD_SOUND_MARINE_RESOURCES_LOW:
theSoundPtr = kMarineLowResources;
theSoundLength = 2.0f;
break;
case HUD_SOUND_MARINE_NEEDS_AMMO:
if(rand() % 2)
theSoundPtr = kMarineNeedsAmmo1;
else
theSoundPtr = kMarineNeedsAmmo2;
theSoundLength = 1.5f;
break;
case HUD_SOUND_MARINE_NEEDS_HEALTH:
if(rand() % 2)
theSoundPtr = kMarineNeedsHealth1;
else
theSoundPtr = kMarineNeedsHealth2;
theSoundLength = 1.3f;
break;
case HUD_SOUND_MARINE_NEEDS_ORDER:
if(rand() % 2)
theSoundPtr = kMarineNeedsOrder1;
else
theSoundPtr = kMarineNeedsOrder2;
theSoundLength = 1.5f;
break;
case HUD_SOUND_MARINE_SOLDIER_LOST:
if(rand() % 2)
theSoundPtr = kMarineSoldierLost1;
else
theSoundPtr = kMarineSoldierLost2;
theSoundLength = 1.3f;
break;
case HUD_SOUND_MARINE_SENTRYFIRING:
if(rand() % 2)
theSoundPtr = kMarineSentryFiring1;
else
theSoundPtr = kMarineSentryFiring2;
theSoundLength = 1.3f;
break;
case HUD_SOUND_MARINE_SENTRYDAMAGED:
if(rand() % 2)
theSoundPtr = kMarineSentryTakingDamage1;
else
theSoundPtr = kMarineSentryTakingDamage2;
theSoundLength = 1.5f;
break;
case HUD_SOUND_MARINE_GIVEORDERS:
// tankefugl: 0000407
if (theAutoHelpEnabled)
{
theSoundPtr = kMarineGiveOrders;
theSoundLength = 2.2f;
}
// :tankefugl
break;
case HUD_SOUND_MARINE_NEEDPORTAL:
// tankefugl: 0000407
if (theAutoHelpEnabled)
{
if(rand() % 2)
theSoundPtr = kMarineNeedPortal1;
else
theSoundPtr = kMarineNeedPortal2;
theSoundLength = 1.8f;
}
// :tankefugl
break;
case HUD_SOUND_MARINE_GOTOALERT:
// tankefugl: 0000407
if (theAutoHelpEnabled)
{
theSoundPtr = kMarineGotoAlert;
theSoundLength = 2.2f;
}
// :tankefugl
break;
case HUD_SOUND_MARINE_COMMANDERIDLE:
// tankefugl: 0000407
if (theAutoHelpEnabled)
{
if(rand() % 2)
theSoundPtr = kMarineCommanderIdle1;
else
theSoundPtr = kMarineCommanderIdle2;
theSoundLength = 1.5f;
}
// :tankefugl
break;
case HUD_SOUND_MARINE_ARMORYUPGRADING:
theSoundPtr = kMarineArmoryUpgrading;
theSoundLength = 3.4;
break;
case HUD_SOUND_ALIEN_ENEMY_APPROACHES:
if(rand() %2)
theSoundPtr = kAlienEnemyApproaches1;
else
theSoundPtr = kAlienEnemyApproaches2;
theSoundLength = 1.6;
break;
case HUD_SOUND_ALIEN_GAMEOVERMAN:
theSoundPtr = kAlienGameOverMan;
theSoundLength = 2.2f;
break;
case HUD_SOUND_ALIEN_HIVE_ATTACK:
theSoundPtr = kAlienHiveAttack;
theSoundLength = 1.6f;
break;
case HUD_SOUND_ALIEN_HIVE_COMPLETE:
if(rand() % 2)
theSoundPtr = kAlienHiveComplete1;
else
theSoundPtr = kAlienHiveComplete2;
theSoundLength = 2.1f;
break;
case HUD_SOUND_ALIEN_HIVE_DYING:
if(rand() % 2)
{
theSoundPtr = kAlienHiveDying1;
theSoundLength = 1.7f;
}
else
{
theSoundPtr = kAlienHiveDying2;
theSoundLength = 2.4f;
}
break;
case HUD_SOUND_ALIEN_LIFEFORM_ATTACK:
if(rand() % 2)
theSoundPtr = kAlienLifeformAttack1;
else
theSoundPtr = kAlienLifeformAttack2;
theSoundLength = 1.8f;
break;
case HUD_SOUND_ALIEN_RESOURCES_LOW:
theSoundPtr = kAlienLowResources;
theSoundLength = 1.7f;
break;
case HUD_SOUND_ALIEN_MESS:
theSoundPtr = kAlienMess;
theSoundLength = 2.0f;
break;
case HUD_SOUND_ALIEN_MORE:
if(rand() % 2)
theSoundPtr = kAlienMoreResources1;
else
theSoundPtr = kAlienMoreResources2;
theSoundLength = 1.8f;
break;
case HUD_SOUND_ALIEN_NEED_BUILDERS:
if(rand() % 2)
theSoundPtr = kAlienNeedBuilders1;
else
theSoundPtr = kAlienNeedBuilders2;
theSoundLength = 1.4f;
break;
case HUD_SOUND_ALIEN_NEED_BETTER:
theSoundPtr = kAlienNeedBetter;
theSoundLength = 2.5f;
break;
case HUD_SOUND_ALIEN_NOW_DONCE:
theSoundPtr = kAlienNowDonce;
theSoundLength = 2.1f;
break;
case HUD_SOUND_ALIEN_NEW_TRAIT:
if(rand() % 2)
theSoundPtr = kAlienNewTrait1;
else
theSoundPtr = kAlienNewTrait2;
theSoundLength = 1.5f;
break;
case HUD_SOUND_ALIEN_POINTS_RECEIVED:
theSoundPtr = kAlienPointsReceivedSound;
theSoundLength = 1.57f;
break;
case HUD_SOUND_ALIEN_RESOURCES_ATTACK:
if(rand() % 2)
theSoundPtr = kAlienResourceAttack1;
else
theSoundPtr = kAlienResourceAttack2;
theSoundLength = 2.1f;
break;
case HUD_SOUND_ALIEN_STRUCTURE_ATTACK:
if(rand() % 2)
theSoundPtr = kAlienStructureAttack1;
else
theSoundPtr = kAlienStructureAttack2;
theSoundLength = 1.9f;
break;
case HUD_SOUND_ALIEN_UPGRADELOST:
theSoundPtr = kAlienUpgradeLost;
theSoundLength = 1.5f;
break;
case HUD_SOUND_ORDER_MOVE:
switch(rand() % 4)
{
case 0:
theSoundPtr = kSoundOrderMove1;
theSoundLength = 1.8f;
break;
case 1:
theSoundPtr = kSoundOrderMove2;
theSoundLength = 2.3f;
break;
case 2:
theSoundPtr = kSoundOrderMove3;
theSoundLength = 1.9f;
break;
case 3:
theSoundPtr = kSoundOrderMove4;
theSoundLength = 2.3f;
break;
}
break;
case HUD_SOUND_ORDER_ATTACK:
theSoundPtr = kSoundOrderAttack;
break;
case HUD_SOUND_ORDER_BUILD:
theSoundPtr = kSoundOrderBuild;
break;
case HUD_SOUND_ORDER_WELD:
theSoundPtr = kSoundOrderWeld;
break;
case HUD_SOUND_ORDER_GUARD:
theSoundPtr = kSoundOrderGuard;
break;
case HUD_SOUND_ORDER_GET:
theSoundPtr = kSoundOrderGet;
break;
case HUD_SOUND_ORDER_COMPLETE:
switch(rand() % 6)
{
case 0:
theSoundPtr = kSoundOrderComplete1;
theSoundLength = 1.6f;
break;
case 1:
theSoundPtr = kSoundOrderComplete2;
theSoundLength = 1.9f;
break;
case 2:
theSoundPtr = kSoundOrderComplete3;
theSoundLength = 1.9f;
break;
case 3:
theSoundPtr = kSoundOrderComplete4;
theSoundLength = 1.4f;
break;
case 4:
theSoundPtr = kSoundOrderComplete5;
theSoundLength = 1.6f;
break;
case 5:
theSoundPtr = kSoundOrderComplete6;
theSoundLength = 1.4f;
break;
}
break;
case HUD_SOUND_GAMESTART:
if(this->GetIsMarine())
{
if(rand() % 2)
theSoundPtr = kMarineGameStart1;
else
theSoundPtr = kMarineGameStart2;
theSoundLength = 1.9f;
}
else if(this->GetIsAlien())
{
if(rand() % 2)
theSoundPtr = kAlienGameStart1;
else
theSoundPtr = kAlienGameStart2;
theSoundLength = 2.2f;
}
break;
case HUD_SOUND_YOU_WIN:
theSoundPtr = kYouWinSound;
theSoundLength = 6.0f;
break;
case HUD_SOUND_YOU_LOSE:
theSoundPtr = kYouLoseSound;
theSoundLength = 6.0f;
break;
case HUD_SOUND_TOOLTIP:
theSoundPtr = kTooltipSound;
// Tooltip sounds should never stop other sounds
theSoundLength = -1.0f;
theVolume = .6f;
break;
// joev: bug 0000767
case HUD_SOUND_PLAYERJOIN:
theSoundPtr = kPlayerJoinedSound;
theSoundLength = 3.0f;
theVolume = 1.1;
break;
// :joev
}
if(theSoundPtr)
{
gEngfuncs.pfnPlaySoundByName(theSoundPtr, theVolume);
if(theSoundLength >= 0.0f)
{
this->mTimeOfNextHudSound = this->mTimeOfCurrentUpdate + theSoundLength;
}
this->mLastHUDSoundPlayed = inSound;
}
}
}
BIND_MESSAGE(SetTech);
int AvHHud::SetTech(const char* pszName, int iSize, void* pbuf)
{
AvHTechNode* theTechNode = NULL;
NetMsg_SetTechNode( pbuf, iSize, theTechNode );
this->mTechNodes.InsertNode(theTechNode);
delete theTechNode;
return 1;
}
BIND_MESSAGE(TechSlots);
int AvHHud::TechSlots(const char* pszName, int iSize, void* pbuf)
{
AvHTechSlots theNewTechSlots;
NetMsg_SetTechSlots( pbuf, iSize, theNewTechSlots );
this->mTechSlotManager.AddTechSlots(theNewTechSlots);
return 1;
}
BIND_MESSAGE(DebugCSP);
int AvHHud::DebugCSP(const char* pszName, int iSize, void* pbuf)
{
weapon_data_t weapon_data;
float next_attack;
NetMsg_DebugCSP( pbuf, iSize, weapon_data, next_attack );
char theServerInfoString[512];
sprintf(theServerInfoString, "Server: id: %d, clip: %d, prim attack: %f, idle: %f, next attack: %f",
weapon_data.m_iId,
weapon_data.m_iClip,
weapon_data.m_flNextPrimaryAttack,
weapon_data.m_flTimeWeaponIdle,
weapon_data.m_flNextSecondaryAttack,
next_attack
);
vgui::Label* theLabel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kDebugCSPServerLabel, theLabel))
{
theLabel->setText(theServerInfoString);
}
return 1;
}
AvHVisibleBlipList& AvHHud::GetEnemyBlipList()
{
return this->mEnemyBlips;
}
AvHEntityHierarchy& AvHHud::GetEntityHierarchy()
{
return this->mEntityHierarchy;
}
AvHVisibleBlipList& AvHHud::GetFriendlyBlipList()
{
return this->mFriendlyBlips;
}
bool AvHHud::GetMouseOneDown() const
{
return this->mMouseOneDown;
}
bool AvHHud::GetMouseTwoDown() const
{
return this->mMouseTwoDown;
}
void AvHHud::HideProgressStatus()
{
if(this->mGenericProgressBar)
{
this->mGenericProgressBar->setVisible(false);
}
if(this->mAlienProgressBar)
{
this->mAlienProgressBar->setVisible(false);
}
}
void AvHHud::HideResearchProgressStatus()
{
if(this->mResearchProgressBar)
{
this->mResearchProgressBar->setVisible(false);
this->mResearchLabel->setVisible(false);
}
}
void AvHHud::Init(void)
{
UIHud::Init();
HOOK_MESSAGE(EntHier);
HOOK_MESSAGE(Particles);
HOOK_MESSAGE(SoundNames);
HOOK_MESSAGE(PlayHUDNot);
HOOK_MESSAGE(BalanceVar);
HOOK_MESSAGE(GameStatus);
HOOK_MESSAGE(Progress);
HOOK_MESSAGE(Countdown);
HOOK_MESSAGE(MiniMap);
HOOK_MESSAGE(SetOrder);
HOOK_MESSAGE(SetSelect);
HOOK_MESSAGE(SetRequest);
HOOK_MESSAGE(SetupMap);
HOOK_MESSAGE(SetTopDown);
HOOK_MESSAGE(SetTech);
HOOK_MESSAGE(EditPS);
HOOK_MESSAGE(Fog);
HOOK_MESSAGE(ListPS);
HOOK_MESSAGE(SetGmma);
HOOK_MESSAGE(BlipList);
HOOK_MESSAGE(ClScript);
HOOK_MESSAGE(AlienInfo);
HOOK_MESSAGE(DebugCSP);
HOOK_MESSAGE(TechSlots);
// tankefugl: 0000971
HOOK_MESSAGE(IssueOrder);
// :tankefugl
HOOK_MESSAGE(ServerVar);
this->AddCommands();
this->mCountDownClock = -1;
mOverviewMap.Clear();
this->mEntityHierarchy.Clear();
//this->mUpgradeCosts.clear();
sPregameGammaTable.InitializeFromVideoState();
sGameGammaTable.InitializeFromVideoState();
int theRC = atexit(AvHHud::ResetGammaAtExit);
_onexit_t theExit = _onexit(AvHHud::ResetGammaAtExitForOnExit);
signal(SIGILL, AvHHud::ResetGammaAtExit);
signal(SIGFPE, AvHHud::ResetGammaAtExit);
signal(SIGSEGV, AvHHud::ResetGammaAtExit);
signal(SIGTERM, AvHHud::ResetGammaAtExit);
signal(SIGBREAK, AvHHud::ResetGammaAtExit);
signal(SIGABRT, AvHHud::ResetGammaAtExit);
//memset(this->mAlienUILifeforms, 0, sizeof(HSPRITE)*kNumAlienLifeforms);
this->mAlienUIUpgrades = 0;
this->mAlienUIUpgradeCategories = 0;
this->mOrderSprite = 0;
this->mCursorSprite = 0;
this->mMarineCursor = 0;
this->mAlienCursor = 0;
this->mMarineUIJetpackSprite = 0;
this->mMembraneSprite = 0;
this->mBackgroundSprite = 0;
this->mProgressBarEntityIndex = -1;
this->mProgressBarParam = -1;
this->mSelectedNodeResourceCost = -1;
this->mCurrentUseableEnergyLevel = 0;
this->mVisualEnergyLevel = 0.0f;
this->mFogActive = false;
this->mFogColor.x = this->mFogColor.y = this->mFogColor.z = 0;
this->mFogStart = 0;
this->mFogEnd = 0;
this->mLocationText = "";
this->mInfoLocationList.clear();
this->mLastHotkeySelectionEvent = MESSAGE_NULL;
this->mUpgrades.clear();
this->mLastGhostBuilding = NULL;
this->mReticleInfoText = "";
this->mSelectingWeaponID = -1;
this->mSelectingNodeID = MESSAGE_NULL;
this->mDesiredGammaSlope = 1;
this->mTimeOfLastHelpText = -1;
this->mCurrentWeaponID = -1;
this->mCurrentWeaponEnabled = false;
this->mCurrentUIMode = MAIN_MODE;
this->mMenuTechSlots = 0;
this->mBlinkingAlertType = 0;
this->mLastUser3 = AVH_USER3_NONE;
this->mLastTeamNumber = TEAM_IND;
this->mLastPlayMode = PLAYMODE_UNDEFINED;
this->mCrosshairShowCount = 1;
this->mCrosshairSprite = 0;
this->mCrosshairR = 0;
this->mCrosshairG = 0;
this->mCrosshairB = 0;
this->mDrawCombatUpgradeMenu = false;
// Initialize viewport
this->mViewport[0] = this->mViewport[1] = this->mViewport[2] = this->mViewport[3] = 0;
gl_monolights = gEngfuncs.pfnGetCvarPointer("gl_monolights");
gl_overbright = gEngfuncs.pfnGetCvarPointer("gl_overbright");
gl_clear = gEngfuncs.pfnGetCvarPointer("gl_clear");
hud_draw = gEngfuncs.pfnGetCvarPointer("hud_draw");
r_drawviewmodel = gEngfuncs.pfnGetCvarPointer("r_drawviewmodel");
gl_d3dflip = gEngfuncs.pfnGetCvarPointer("gl_d3dflip");
s_show = gEngfuncs.pfnGetCvarPointer("s_show");
lightgamma = gEngfuncs.pfnGetCvarPointer("lightgamma");
r_detailtextures = gEngfuncs.pfnGetCvarPointer("r_detailtextures");
gl_max_size = gEngfuncs.pfnGetCvarPointer("gl_max_size");
}
// This gives the HUD a chance to draw after the VGUI. A component must allow itself to be hooked by calling this function
// at the end of it's paint() routine. This is done so the mouse cursor can draw on top of the other components.
void AvHHud::ComponentJustPainted(Panel* inPanel)
{
// if(this->GetInTopDownMode())
// {
// AvHTeamHierarchy* theComponent = dynamic_cast<AvHTeamHierarchy*>(inPanel);
// if(theComponent)
// {
// int theBasePosX;
// int theBasePosY;
// theComponent->getPos(theBasePosX, theBasePosY);
// this->DrawMouseCursor(theBasePosX, theBasePosY);
// }
// }
// else
// {
// PieMenu* theComponent = dynamic_cast<PieMenu*>(inPanel);
// if(theComponent)
// {
// int theBasePosX;
// int theBasePosY;
// theComponent->getPos(theBasePosX, theBasePosY);
// this->DrawMouseCursor(theBasePosX, theBasePosY);
// }
// }
DummyPanel* theComponent = dynamic_cast<DummyPanel*>(inPanel);
if(theComponent)
{
int theBasePosX;
int theBasePosY;
theComponent->getPos(theBasePosX, theBasePosY);
this->DrawMouseCursor(theBasePosX, theBasePosY);
}
}
bool AvHHud::SetCursor(AvHOrderType inOrderType)
{
bool theSuccess = false;
if(!this->GetIsAlien())
{
this->mCursorSprite = this->mMarineCursor;
if((inOrderType >= 0) && (inOrderType < ORDERTYPE_MAX))
{
this->mCurrentCursorFrame = (int)(inOrderType);
theSuccess = true;
}
// Change cursor when over a valid choice
if(this->mSelectingNodeID > 0)
{
this->mCurrentCursorFrame = 1;
theSuccess = true;
}
}
else
{
this->mCursorSprite = this->mAlienCursor;
this->mCurrentCursorFrame = 0;
if(this->mSelectingNodeID > 0)
{
// Set cursor to lifeform to evolve to
switch(this->mSelectingNodeID)
{
case ALIEN_LIFEFORM_ONE:
case ALIEN_LIFEFORM_TWO:
case ALIEN_LIFEFORM_THREE:
case ALIEN_LIFEFORM_FOUR:
case ALIEN_LIFEFORM_FIVE:
this->mCurrentCursorFrame = 2 + (int)this->mSelectingNodeID - (int)ALIEN_LIFEFORM_ONE;
break;
default:
this->mCurrentCursorFrame = 1;
break;
}
}
theSuccess = true;
}
// Scheme::SchemeCursor theSchemeCursor = Scheme::SchemeCursor::scu_arrow;
// //Scheme::SchemeCursor theSchemeCursor = Scheme::SchemeCursor::scu_no;
//
// switch(inOrderType)
// {
//// case ORDERTYPE_UNDEFINED:
//// theSchemeCursor = Scheme::SchemeCursor::scu_no;
//// theSuccess = true;
//// break;
//
// //case ORDERTYPEL_MOVE:
//
// case ORDERTYPET_ATTACK:
// case ORDERTYPET_GUARD:
// case ORDERTYPET_WELD:
// case ORDERTYPET_BUILD:
// case ORDERTYPEL_USE:
// case ORDERTYPET_GET:
// theSchemeCursor = Scheme::SchemeCursor::scu_hand;
// theSuccess = true;
// break;
// }
//
// App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(theSchemeCursor));
return theSuccess;
}
void AvHHud::GetCursor(HSPRITE& outSprite, int& outFrame)
{
if (g_iUser1 == 0)
{
outSprite = mCursorSprite;
outFrame = mCurrentCursorFrame;
}
else
{
// Always use the marine cursor in spectator mode.
outSprite = mMarineCursor;
outFrame = 0;
}
}
void AvHHud::SetHelpMessage(const string& inHelpText, bool inForce, float inNormX, float inNormY)
{
if(inForce || gEngfuncs.pfnGetCvarFloat(kvAutoHelp))
{
float theReticleX = kHelpMessageLeftEdgeInset;
float theReticleY = kHelpMessageTopEdgeInset - 0.03f; // + 0.15f;
bool theCentered = false;
if(this->GetInTopDownMode())
{
int theMouseX, theMouseY;
this->GetMousePos(theMouseX, theMouseY);
theReticleX = theMouseX/(float)ScreenWidth();
theReticleY = theMouseY/(float)ScreenHeight();
// Move text up a bit so it doesn't obscure
theReticleY -= .1f;
theCentered = true;
}
// Alien HUD forces this to be inset a bit
else
{
if(this->GetIsAlien())
{
theReticleX = kHelpMessageAlienLeftedgeInset;
theReticleY = kHelpMessageAlienTopEdgeInset - 0.15f;
}
if(inNormX != -1)
{
theReticleX = inNormX;
}
if(inNormY != -1)
{
theReticleY = inNormY;
}
}
this->mHelpMessage.SetText(inHelpText);
this->mHelpMessage.SetNormalizedScreenX(theReticleX);
this->mHelpMessage.SetNormalizedScreenY(theReticleY);
this->mHelpMessage.SetCentered(theCentered);
this->mHelpMessage.SetNormalizedMaxWidth(kReticleMaxWidth);
//this->mHelpMessage.SetIgnoreFadeForLifetime(true);
float theTimePassed = (this->mTimeOfCurrentUpdate - this->mTimeOfLastUpdate);
this->mHelpMessage.FadeText(theTimePassed, false);
// Set color
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
this->mHelpMessage.SetRGB(theR, theG, theB);
}
}
void AvHHud::SetActionButtonHelpMessage(const string& inHelpText)
{
this->mTopDownActionButtonHelp.SetText(inHelpText);
const float kNormX = .73f;
this->mTopDownActionButtonHelp.SetNormalizedScreenX(kNormX);
// Treat this as the bottom of the tooltip. Scale the tooltip so it's bottom is here.
const float kNormY = .68f;
int theHeight = this->mTopDownActionButtonHelp.GetScreenHeight();
float theNormalizedHeight = (float)theHeight/ScreenHeight();
this->mTopDownActionButtonHelp.SetNormalizedScreenY(kNormY - theNormalizedHeight);
this->mTopDownActionButtonHelp.SetBackgroundA(128);
this->mTopDownActionButtonHelp.SetCentered(false);
this->mTopDownActionButtonHelp.SetNormalizedMaxWidth(1.0f - kNormX - .01f);
//this->mTopDownActionButtonHelp.SetIgnoreFadeForLifetime(true);
float theTimePassed = (this->mTimeOfCurrentUpdate - this->mTimeOfLastUpdate);
this->mTopDownActionButtonHelp.FadeText(theTimePassed, false);
// Set color
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
this->mTopDownActionButtonHelp.SetRGB(theR, theG, theB);
}
void AvHHud::SetReticleMessage(const string& inHelpText)
{
float theReticleX;
float theReticleY;
bool theIsCentered;
this->GetReticleTextDrawingInfo(theReticleX, theReticleY, theIsCentered);
this->mReticleMessage.SetText(inHelpText);
this->mReticleMessage.SetNormalizedScreenX(theReticleX);
this->mReticleMessage.SetNormalizedScreenY(theReticleY);
this->mReticleMessage.SetCentered(theIsCentered);
this->mReticleMessage.SetNormalizedMaxWidth(kReticleMaxWidth);
// Need instant fade-in and slow fade down for player names and info
this->mReticleMessage.SetFadeDownSpeed(-100);
this->mReticleMessage.SetFadeUpSpeed(10000);
//this->mReticleMessage.SetIgnoreFadeForLifetime(true);
float theTimePassed = (this->mTimeOfCurrentUpdate - this->mTimeOfLastUpdate);
this->mReticleMessage.FadeText(theTimePassed, false);
}
void AvHHud::SetCurrentUseableEnergyLevel(float inEnergyLevel)
{
this->mCurrentUseableEnergyLevel = inEnergyLevel;
}
const AvHMapExtents& AvHHud::GetMapExtents()
{
return this->mMapExtents;
}
void AvHHud::InitCommanderMode()
{
Panel* thePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kLeaveCommanderButton, thePanel))
{
thePanel->addInputSignal(&gCommanderHandler);
}
if(this->GetManager().GetVGUIComponentNamed(kHierarchy, thePanel))
{
thePanel->addInputSignal(&gCommanderHandler);
}
if(this->GetManager().GetVGUIComponentNamed(kActionButtonsComponents, thePanel))
{
thePanel->addInputSignal(&gCommanderHandler);
}
if(this->GetManager().GetVGUIComponentNamed(kSelectAllImpulsePanel, thePanel))
{
thePanel->addInputSignal(&gCommanderHandler);
}
// Add handler for all pending request buttons
for(int i = 0; i < MESSAGE_LAST; i++)
{
AvHMessageID theMessageID = AvHMessageID(i);
char theComponentName[256];
sprintf(theComponentName, kPendingImpulseSpecifier, (int)theMessageID);
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(theComponentName, theTechImpulsePanel))
{
theTechImpulsePanel->addInputSignal(&gCommanderHandler);
}
}
//this->GetManager().GetVGUIComponentNamed(kScroller, thePanel);
//if(thePanel)
//{
// thePanel->addInputSignal(&gScrollHandler);
//}
// Get input from every control
this->GetManager().AddInputSignal(&gScrollHandler);
// TODO: Add others here
}
// Read in base state from stream (called by Demo_ReadBuffer)
int AvHHud::InitializeDemoPlayback(int inSize, unsigned char* inBuffer)
{
// Read in base state
int theBytesRead = 0;
// Read in num upgrades
int theNumUpgrades = 0;
//this->mUpgradeCosts.clear();
LoadData(&theNumUpgrades, inBuffer, sizeof(int), theBytesRead);
for(int i = 0; i < theNumUpgrades; i++)
{
// Read in upgrades (for backwards-compatibility)
int theFirst = 0;
LoadData(&theFirst, inBuffer, sizeof(int), theBytesRead);
int theSecond = 0;
LoadData(&theSecond, inBuffer, sizeof(int), theBytesRead);
}
// Read in gamma
LoadData(&this->mDesiredGammaSlope, inBuffer, sizeof(this->mDesiredGammaSlope), theBytesRead);
if (!mSteamUIActive)
{
this->SetGamma(this->mDesiredGammaSlope);
}
// Read in resources
LoadData(&this->mResources, inBuffer, sizeof(this->mResources), theBytesRead);
// Read in commander (TODO: REMOVE)
int theCommander;
LoadData(&theCommander, inBuffer, sizeof(theCommander), theBytesRead);
// Read in number of hive infos
this->mHiveInfoList.clear();
int theNumHiveInfos = 0;
LoadData(&theNumHiveInfos, inBuffer, sizeof(int), theBytesRead);
// For each one, add a new hive info
for(i = 0; i < theNumHiveInfos; i++)
{
AvHHiveInfo theHiveInfo;
LoadData(&theHiveInfo, inBuffer, sizeof(AvHHiveInfo), theBytesRead);
this->mHiveInfoList.push_back(theHiveInfo);
}
// Load and set current pie menu control
int thePieMenuControlLength = 0;
LoadData(&thePieMenuControlLength, inBuffer, sizeof(int), theBytesRead);
char thePieMenuControl[256];
memset(thePieMenuControl, 0, 256);
LoadData(thePieMenuControl, inBuffer, thePieMenuControlLength, theBytesRead);
this->mPieMenuControl = string(thePieMenuControl);
// Read in selected units size
this->mSelected.clear();
int theNumSelected = 0;
LoadData(&theNumSelected, inBuffer, sizeof(theNumSelected), theBytesRead);
for(i = 0; i < theNumSelected; i++)
{
// Read in selected units
EntityInfo theSelectedEntity = 0;
LoadData(&theSelectedEntity, inBuffer, sizeof(theSelectedEntity), theBytesRead);
}
ASSERT((theBytesRead + (int)sizeof(int)) == inSize);
// Clear existing particle system templates
gParticleTemplateList.Clear();
AvHParticleSystemManager::Instance()->Reset();
// Clear weapon info
gWR.Reset();
return theBytesRead;
}
int AvHHud::InitializeDemoPlayback2(int inSize, unsigned char* inBuffer)
{
// Read in base state 2
int theBytesRead = 0;
LOAD_DATA(this->mTimeOfLastUpdate);
LOAD_DATA(this->mTimeOfNextHudSound);
LOAD_DATA(this->mTimeOfCurrentUpdate);
LOAD_DATA(this->mCountDownClock);
LOAD_DATA(this->mLastTickPlayed);
LOAD_DATA(this->mNumTicksToPlay);
LoadStringData(this->mMapName, inBuffer, theBytesRead);
float theMinViewHeight;
LOAD_DATA(theMinViewHeight);
this->mMapExtents.SetMinViewHeight(theMinViewHeight);
float theMaxViewHeight;
LOAD_DATA(theMaxViewHeight);
this->mMapExtents.SetMaxViewHeight(theMaxViewHeight);
float theMinMapX;
LOAD_DATA(theMinMapX);
this->mMapExtents.SetMinMapX(theMinMapX);
float theMaxMapX;
LOAD_DATA(theMaxMapX);
this->mMapExtents.SetMaxMapX(theMaxMapX);
float theMinMapY;
LOAD_DATA(theMinMapY);
this->mMapExtents.SetMinMapY(theMinMapY);
float theMaxMapY;
LOAD_DATA(theMaxMapY);
this->mMapExtents.SetMaxMapY(theMaxMapY);
bool theDrawMapBG;
LOAD_DATA(theDrawMapBG);
this->mMapExtents.SetDrawMapBG(theDrawMapBG);
// Clear then load sound names
int theSoundNameListSize;
LOAD_DATA(theSoundNameListSize);
this->mSoundNameList.clear();
for(int i = 0; i < theSoundNameListSize; i++)
{
string theCurrentSoundName;
LoadStringData(theCurrentSoundName, inBuffer, theBytesRead);
this->mSoundNameList.push_back(theCurrentSoundName);
}
ASSERT((theBytesRead + (int)sizeof(int)) == inSize);
return theBytesRead;
}
// Write out base HUD data to stream
void AvHHud::InitializeDemoRecording()
{
// Figure out total size of buffer needed
// Write number of upgrades, then each upgrade
// No longer done, but need to add in upgrades for backwards compatibility
int theUpgrades = 0;
int theUpgradesSize = sizeof(theUpgrades);
// Gamma, resources
int theGammaSize = sizeof(this->mDesiredGammaSlope);
int theResourcesSizes = sizeof(this->mResources);
// Save commander index (TODO: REMOVE)
int theCommanderIndex = this->GetCommanderIndex();
int theCommanderSize = sizeof(theCommanderIndex);
int theNumHiveInfoRecords = (int)this->mHiveInfoList.size();
int theHiveInfoSize = sizeof(int) + theNumHiveInfoRecords*sizeof(AvHHiveInfo);
string thePieMenuControl = gPieMenuHandler.GetPieMenuControl();
int theCurrentPieMenuControlSize = sizeof(int) + (int)thePieMenuControl.size();
int theSelectedSize = sizeof(int) + (int)this->mSelected.size()*sizeof(EntityInfo);
int theTotalSize = theUpgradesSize + theGammaSize + theResourcesSizes + theCommanderSize + theHiveInfoSize + theCurrentPieMenuControlSize + theSelectedSize;
// New a char array of this size
int theCounter = 0;
unsigned char* theCharArray = new unsigned char[theTotalSize];
if(theCharArray)
{
// Write out number of upgrades (for backwards-compatibility)
int theNumUpgradeCosts = 0;
SaveData(theCharArray, &theNumUpgradeCosts, sizeof(theNumUpgradeCosts), theCounter);
// Write out gamma
SaveData(theCharArray, &this->mDesiredGammaSlope, theGammaSize, theCounter);
SaveData(theCharArray, &this->mResources, theResourcesSizes, theCounter);
SaveData(theCharArray, &theCommanderIndex, theCommanderSize, theCounter);
// Write out num hive info records
SaveData(theCharArray, &theNumHiveInfoRecords, sizeof(int), theCounter);
for(HiveInfoListType::iterator theHiveInfoIter = this->mHiveInfoList.begin(); theHiveInfoIter != this->mHiveInfoList.end(); theHiveInfoIter++)
{
SaveData(theCharArray, &(*theHiveInfoIter), sizeof(AvHHiveInfo), theCounter);
}
// Save length of pie menu control name
int thePieMenuControlNameLength = (int)thePieMenuControl.size();
SaveData(theCharArray, &thePieMenuControlNameLength, sizeof(int), theCounter);
SaveData(theCharArray, thePieMenuControl.c_str(), thePieMenuControlNameLength, theCounter);
// Save out size of selected
int theNumSelected = (int)this->mSelected.size();
SaveData(theCharArray, &theNumSelected, sizeof(theNumSelected), theCounter);
for(EntityListType::const_iterator theSelectedIter = this->mSelected.begin(); theSelectedIter != this->mSelected.end(); theSelectedIter++)
{
EntityInfo theCurrentInfo = *theSelectedIter;
SaveData(theCharArray, &theCurrentInfo, sizeof(EntityInfo), theCounter);
}
ASSERT(theCounter == theTotalSize);
// Write it out
Demo_WriteBuffer(TYPE_BASESTATE, theTotalSize, theCharArray);
// Delete char array
delete [] theCharArray;
theCharArray = NULL;
// Save out particle templates
gParticleTemplateList.InitializeDemoRecording();
}
theTotalSize = theCounter = 0;
theTotalSize += sizeof(this->mTimeOfLastUpdate);
theTotalSize += sizeof(this->mTimeOfNextHudSound);
theTotalSize += sizeof(this->mTimeOfCurrentUpdate);
theTotalSize += sizeof(this->mCountDownClock);
theTotalSize += sizeof(this->mLastTickPlayed);
theTotalSize += sizeof(this->mNumTicksToPlay);
theTotalSize += GetDataSize(this->mMapName);
theTotalSize += sizeof(this->mMapExtents.GetMinViewHeight());
theTotalSize += sizeof(this->mMapExtents.GetMaxViewHeight());
theTotalSize += sizeof(this->mMapExtents.GetMinMapX());
theTotalSize += sizeof(this->mMapExtents.GetMaxMapX());
theTotalSize += sizeof(this->mMapExtents.GetMinMapY());
theTotalSize += sizeof(this->mMapExtents.GetMaxMapY());
theTotalSize += sizeof(this->mMapExtents.GetDrawMapBG());
// Save sound names
int theSoundNameListSize = (int)this->mSoundNameList.size();
theTotalSize += sizeof(theSoundNameListSize);
for(int i = 0; i < theSoundNameListSize; i++)
{
string theCurrentSoundName = this->mSoundNameList[i];
theTotalSize += GetDataSize(theCurrentSoundName);
}
theCharArray = new unsigned char[theTotalSize];
if(theCharArray)
{
SAVE_DATA(this->mTimeOfLastUpdate);
SAVE_DATA(this->mTimeOfNextHudSound);
SAVE_DATA(this->mTimeOfCurrentUpdate);
SAVE_DATA(this->mCountDownClock);
SAVE_DATA(this->mLastTickPlayed);
SAVE_DATA(this->mNumTicksToPlay);
SaveStringData(theCharArray, this->mMapName, theCounter);
float theMinViewHeight = this->mMapExtents.GetMinViewHeight();
SAVE_DATA(theMinViewHeight);
float theMaxViewHeight = this->mMapExtents.GetMaxViewHeight();
SAVE_DATA(theMaxViewHeight);
float theMinMapX = this->mMapExtents.GetMinMapX();
SAVE_DATA(theMinMapX);
float theMaxMapX = this->mMapExtents.GetMaxMapX();
SAVE_DATA(theMaxMapX);
float theMinMapY = this->mMapExtents.GetMinMapY();
SAVE_DATA(theMinMapY);
float theMaxMapY = this->mMapExtents.GetMaxMapY();
SAVE_DATA(theMaxMapY);
bool theDrawMapBG = this->mMapExtents.GetDrawMapBG();
SAVE_DATA(theDrawMapBG);
SAVE_DATA(theSoundNameListSize);
for(int i = 0; i < theSoundNameListSize; i++)
{
string theCurrentSoundName = this->mSoundNameList[i];
SaveStringData(theCharArray, theCurrentSoundName, theCounter);
}
// TODO: Save out locations?
ASSERT(theCounter == theTotalSize);
// Write out TYPE_BASESTATE2 chunk separately for backwards-compatibility
Demo_WriteBuffer(TYPE_BASESTATE2, theTotalSize, theCharArray);
delete [] theCharArray;
theCharArray = NULL;
}
ScorePanel_InitializeDemoRecording();
// Write out weapon info
for(i = 0; i < MAX_WEAPONS; i++)
{
WEAPON* theWeapon = gWR.GetWeapon(i);
if( theWeapon )
{
theTotalSize = sizeof(theWeapon->szName) + sizeof(theWeapon->iAmmoType) + sizeof(theWeapon->iAmmo2Type) + sizeof(theWeapon->iMax1) + sizeof(theWeapon->iMax2) + sizeof(theWeapon->iSlot) + sizeof(theWeapon->iSlotPos) + sizeof(theWeapon->iFlags) + sizeof(theWeapon->iId) + sizeof(theWeapon->iClip) + sizeof(theWeapon->iCount);// + sizeof(int); // last one is for ammo
theCharArray = new unsigned char[theTotalSize];
int theWeaponCoreDataLength = theTotalSize;// - sizeof(int);
memcpy(theCharArray, theWeapon, theWeaponCoreDataLength); // Everything but ammo
//int theAmmo = gWR.GetAmmo(theWeapon->iId);
//memcpy(theCharArray + theWeaponCoreDataLength, &theAmmo, sizeof(int));
Demo_WriteBuffer(TYPE_WEAPONINFO, theTotalSize, (unsigned char*)theWeapon);
delete [] theCharArray;
theCharArray = NULL;
}
}
}
int AvHHud::InitializeWeaponInfoPlayback(int inSize, unsigned char* inBuffer)
{
// Make sure weapons are cleared out first
WEAPON theWeapon;
memset(&theWeapon, 0, sizeof(theWeapon));
int theWeaponCoreDataLength = inSize;// - sizeof(int);
memcpy(&theWeapon, inBuffer, theWeaponCoreDataLength);
if(theWeapon.iId)
{
gWR.AddWeapon( &theWeapon );
//int theAmmo = 0;
//memcpy(&theAmmo, inBuffer + theWeaponCoreDataLength, sizeof(int));
//gWR.SetAmmo(theWeapon.iId, theAmmo);
}
return inSize;
}
void AvHHud::InitMenu(const string& inMenuName)
{
PieMenu* theMenu = NULL;
if(this->GetManager().GetVGUIComponentNamed(inMenuName, theMenu))
{
theMenu->AddInputSignalForNodes(&gPieMenuHandler);
//outMenu->DisableNodesGreaterThanCost(this->mResources);
this->GetManager().HideComponent(inMenuName);
}
}
void AvHHud::PostUIInit(void)
{
this->InitMenu(kSoldierMenu);
this->InitMenu(kSoldierCombatMenu);
this->InitMenu(kAlienMenu);
this->InitMenu(kAlienCombatMenu);
this->InitCommanderMode();
this->GetManager().GetVGUIComponentNamed(kCommanderResourceLabel, this->mCommanderResourceLabel);
this->GetManager().GetVGUIComponentNamed(kGenericProgress, this->mGenericProgressBar);
this->GetManager().GetVGUIComponentNamed(kResearchProgress, this->mResearchProgressBar);
this->GetManager().GetVGUIComponentNamed(kAlienProgress, this->mAlienProgressBar);
this->GetManager().GetVGUIComponentNamed(kSelectionBox, this->mSelectionBox);
this->GetManager().GetVGUIComponentNamed(kResearchingLabel, this->mResearchLabel);
// Init particle editor
gParticleEditorHandler.Setup();
if(this->GetManager().GetVGUIComponentNamed(kHierarchy, this->mHierarchy))
{
this->mHierarchy->setEnabled(false);
}
if(this->GetManager().GetVGUIComponentNamed(kShowMapHierarchy, this->mShowMapHierarchy))
{
this->mShowMapHierarchy->setEnabled(false);
}
// Don't turn on gamma by default, it is annoying for testing
//this->SetGamma();
}
AvHMessageID AvHHud::GetGhostBuilding() const
{
return this->mGhostBuilding;
}
void AvHHud::SetGhostBuildingMode(AvHMessageID inGhostBuilding)
{
this->mGhostBuilding = inGhostBuilding;
this->mCreatedGhost = false;
}
void AvHHud::SetClientDebugCSP(weapon_data_t* inWeaponData, float inNextPlayerAttack)
{
char theClientInfoString[512];
sprintf(theClientInfoString, "Client: id: %d, clip: %d, prim attack: %f, idle: %f, next attack: %f", inWeaponData->m_iId, inWeaponData->m_iClip, inWeaponData->m_flNextPrimaryAttack, inWeaponData->m_flTimeWeaponIdle, inNextPlayerAttack);
vgui::Label* theLabel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kDebugCSPClientLabel, theLabel))
{
theLabel->setText(theClientInfoString);
}
}
void AvHHud::SetCurrentWeaponData(int inCurrentWeaponID, bool inEnabled)
{
this->mCurrentWeaponID = inCurrentWeaponID;
this->mCurrentWeaponEnabled = inEnabled;
}
int AvHHud::GetCurrentWeaponID(void)
{
return this->mCurrentWeaponID;
}
void AvHHud::SetAlienAbility(AvHMessageID inAlienAbility)
{
this->mAlienAbility = inAlienAbility;
}
void AvHHud::SetProgressStatus(float inPercentage)
{
if(this->mGenericProgressBar)
{
this->mGenericProgressBar->setVisible(false);
}
if(this->mAlienProgressBar)
{
this->mAlienProgressBar->setVisible(false);
}
ProgressBar* theProgressBar = this->mGenericProgressBar;
if(this->GetIsAlien())
{
theProgressBar = this->mAlienProgressBar;
}
if(theProgressBar)
{
theProgressBar->setVisible(true);
int theNumSegments = theProgressBar->getSegmentCount();
int theSegment = inPercentage*theNumSegments;
theProgressBar->setProgress(theSegment);
}
}
void AvHHud::SetReinforcements(int inReinforcements)
{
Label* theLabel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kReinforcementsLabel, theLabel))
{
string thePrefix;
if(LocalizeString(kReinforcementsText, thePrefix))
{
string theText = thePrefix + string(" ") + MakeStringFromInt(inReinforcements);
theLabel->setText(theText.c_str());
}
}
}
void AvHHud::SetResearchProgressStatus(float inPercentage)
{
if(this->mResearchProgressBar)
{
this->mResearchProgressBar->setVisible(true);
int theNumSegments = this->mResearchProgressBar->getSegmentCount();
int theSegment = inPercentage*theNumSegments;
this->mResearchProgressBar->setProgress(theSegment);
this->mResearchLabel->setVisible(true);
// Center research label
int theX, theY;
this->mResearchLabel->getPos(theX, theY);
int theTextWidth, theTextHeight;
this->mResearchLabel->getTextSize(theTextWidth, theTextHeight);
this->mResearchLabel->setPos(ScreenWidth()/2 - theTextWidth/2, theY);
}
}
void AvHHud::UpdateDemoRecordPlayback()
{
// If the mouse is visible, allow it to work with demos
if(gEngfuncs.pDemoAPI->IsRecording())
{
// Write out first frame if needed
if(!this->mRecordingLastFrame)
{
this->InitializeDemoRecording();
this->mRecordingLastFrame = true;
}
// Write view origin (and angles?)
//Demo_WriteVector(TYPE_VIEWANGLES, v_angles);
//Demo_WriteVector(TYPE_VIEWORIGIN, v_origin);
// Demo_WriteByte(TYPE_MOUSEVIS, g_iVisibleMouse);
//
// if(g_iVisibleMouse)
// {
// int theMouseScreenX, theMouseScreenY;
//
// IN_GetMousePos(&theMouseScreenX, &theMouseScreenY);
//
// //theMouseScreenX += ScreenWidth/2;
// //theMouseScreenY += ScreenHeight/2;
//
// // Write mouse position
// float theNormX = (float)theMouseScreenX/ScreenWidth;
// float theNormY = (float)theMouseScreenY/ScreenHeight;
//
// Demo_WriteFloat(TYPE_MOUSEX, theNormX);
// Demo_WriteFloat(TYPE_MOUSEY, theNormY);
//
// //char theBuffer[256];
// //sprintf(theBuffer, "Saving mouse coords %f %f\n", theNormX, theNormY);
// //CenterPrint(theBuffer);
// }
}
else if(gEngfuncs.pDemoAPI->IsPlayingback())
{
//char theBuffer[256];
//sprintf(theBuffer, "Restoring mouse coords %f %f\n", gNormMouseX, gNormMouseY);
//CenterPrint(theBuffer);
//int theCurrentMouseX = gNormMouseX*ScreenWidth;
//int theCurrentMouseY = gNormMouseY*ScreenHeight;
//
////App::getInstance()->setCursorPos(theCurrentMouseX, theCurrentMouseY);
//
//SetCursorPos(theCurrentMouseX, theCurrentMouseY);
//
//this->mMouseCursorX = theCurrentMouseX;
//this->mMouseCursorY = theCurrentMouseY;
this->mRecordingLastFrame = false;
}
else
{
this->mRecordingLastFrame = false;
}
}
void AvHHud::UpdateDataFromVuser4(float inCurrentTime)
{
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
if(theLocalPlayer)
{
// Fetch data from vuser4
vec3_t theVUser = theLocalPlayer->curstate.vuser4;
//int theVUserVar0 = 0;
//int theVUserVar1 = 0;
//int theVUserVar2 = 0;
//
//memcpy(&theVUserVar0, (int*)(&theVUser.x), 4);
//memcpy(&theVUserVar1, (int*)(&theVUser.y), 4);
//memcpy(&theVUserVar2, (int*)(&theVUser.z), 4);
// Fetch new resource level
//theVUserVar2;// & 0x0000FFFF;
if(this->GetIsCombatMode())
{
this->mExperience = (int)ceil(theVUser.z/kNumericNetworkConstant);
this->mExperienceLevel = AvHPlayerUpgrade::GetPlayerLevel(this->mExperience);
const float kShowMenuInterval = 5.0f;
// If we are at a level greater then we've drawn, set visible again to reparse
if(this->mExperienceLevel > this->mExperienceLevelLastDrawn)
{
this->DisplayCombatUpgradeMenu(true);
this->mTimeOfLastLevelUp = inCurrentTime;
this->mExperienceLevelLastDrawn = this->mExperienceLevel;
}
// else if we have no more levels to spend or if we've been displaying it longer then the time out (+1 because we start at level 1)
else if((this->mExperienceLevel == (this->mExperienceLevelSpent + 1)) || (inCurrentTime > (this->mTimeOfLastLevelUp + kShowMenuInterval)))
{
// stop displaying it
this->DisplayCombatUpgradeMenu(false);
}
}
else
{
int theNewValue = (int)ceil(theVUser.z/kNumericNetworkConstant);
if(theNewValue != this->mResources)
{
this->mResources = theNewValue;
}
// Don't smooth resources nicely when switching targets
if((g_iUser1 == OBS_IN_EYE) && (g_iUser2 != this->mUser2OfLastResourceMessage))
{
this->mVisualResources = this->mResources;
}
}
this->mUser2OfLastResourceMessage = g_iUser2;
}
}
void AvHHud::UpdateSpectating()
{
// If we're spectating and the team of our target switched, delete all blips
if((this->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (this->GetPlayMode() == PLAYMODE_OBSERVER))
{
AvHTeamNumber theCurrentTargetTeam = TEAM_IND;
int theCurrentTarget = g_iUser2;//thePlayer->curstate.iuser2;
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(theCurrentTarget);
if(theEntity)
{
theCurrentTargetTeam = AvHTeamNumber(theEntity->curstate.team);
}
if((theCurrentTargetTeam != this->mLastTeamSpectated) && (theCurrentTargetTeam != TEAM_IND))
{
this->mEnemyBlips.Clear();
this->mFriendlyBlips.Clear();
this->mLastTeamSpectated = theCurrentTargetTeam;
//CenterPrint("Clearing blips.");
}
}
}
void AvHHud::UpdateCommonUI()
{
// Find currently selected node and draw help text if it's been open for a little bit
PieMenu* thePieMenu = NULL;
AvHMessageID theCurrentNodeID = MESSAGE_NULL;
this->mSelectingNodeID = MESSAGE_NULL;
if(this->GetManager().GetVGUIComponentNamed(this->mPieMenuControl, thePieMenu))
{
// tankefugl: Added check to ensure that it is only updated when a menu is visible
if (thePieMenu->getChildCount() > 0)
{
vgui::Panel *rootMenu = thePieMenu->getChild(0);
if (rootMenu && rootMenu->isVisible())
{
this->UpdateUpgradeCosts();
}
}
PieNode* theCurrentNode = NULL;
if(thePieMenu && thePieMenu->GetSelectedNode(theCurrentNode))
{
theCurrentNodeID = (AvHMessageID)theCurrentNode->GetMessageID();
if(theCurrentNodeID > 0)
{
this->mSelectingNodeID = theCurrentNodeID;
}
}
}
// Clear squad on team change
if(!this->GetIsMarine())
{
this->mCurrentSquad = 0;
}
}
#define FORCE_CVAR(a,b) if(a)a->value = b;
void AvHHud::UpdateExploitPrevention()
{
//Note: Sometimes some clients will not have these cvars, so be sure to check that they are not null.
FORCE_CVAR(gl_monolights, 0.0f);
FORCE_CVAR(gl_overbright, 0.0f);
FORCE_CVAR(gl_clear, 0.0f);
FORCE_CVAR(hud_draw, 1.0f);
FORCE_CVAR(r_drawviewmodel, 1.0f);
FORCE_CVAR(cl_movespeedkey, AvHMUGetWalkSpeedFactor(this->GetHUDUser3()));
FORCE_CVAR(gl_d3dflip, 1.0f);
FORCE_CVAR(s_show, 0.0f);
FORCE_CVAR(r_detailtextures, 0.0f);
FORCE_CVAR(gl_max_size, 256.0f);
if(lightgamma && lightgamma->value < 2.0)
lightgamma->value = 2.0f;
}
void AvHHud::UpdateAlienUI(float inCurrentTime)
{
// Always hide it by default
this->GetManager().HideComponent(kPieHelpText);
if(this->GetIsAlien() && this->GetIsAlive())
{
float theTimePassed = inCurrentTime - this->mTimeOfLastUpdate;
// int theNumFrames = SPR_Frames(this->mAlienUIHiveSprite);
//
// for(AnimatedSpriteListType::iterator theIter = this->mAlienUIHiveList.begin(); theIter != this->mAlienUIHiveList.end(); theIter++)
// {
// const float kAnimationSpeed = 16.0f;
//
// float theCurrentFrame = theIter->mCurrentFrame + theTimePassed*kAnimationSpeed;
// if(theCurrentFrame >= theNumFrames)
// {
// theCurrentFrame -= theNumFrames;
// }
// theIter->mCurrentFrame = theCurrentFrame;
// }
// Check to see if we have any unspent upgrades. If so, change the pie menu and HUD state to reflect this
this->mNumUpgradesAvailable = 0;
for(int i = 0; i < ALIEN_UPGRADE_CATEGORY_MAX_PLUS_ONE; i++)
{
this->mCurrentUpgradeCategory[i] = ALIEN_UPGRADE_CATEGORY_INVALID;
}
int theUpgradeVar = this->GetLocalUpgrades();
if(AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_SENSORY, this->mUpgrades, theUpgradeVar))
{
this->mCurrentUpgradeCategory[this->mNumUpgradesAvailable] = ALIEN_UPGRADE_CATEGORY_SENSORY;
this->mNumUpgradesAvailable += 1;
}
if(AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_MOVEMENT, this->mUpgrades, theUpgradeVar))
{
this->mCurrentUpgradeCategory[this->mNumUpgradesAvailable] = ALIEN_UPGRADE_CATEGORY_MOVEMENT;
this->mNumUpgradesAvailable += 1;
}
if(AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_OFFENSE, this->mUpgrades, theUpgradeVar))
{
this->mCurrentUpgradeCategory[this->mNumUpgradesAvailable] = ALIEN_UPGRADE_CATEGORY_OFFENSE;
this->mNumUpgradesAvailable += 1;
}
if(AvHGetHasUpgradeChoiceInCategory(ALIEN_UPGRADE_CATEGORY_DEFENSE, this->mUpgrades, theUpgradeVar))
{
this->mCurrentUpgradeCategory[this->mNumUpgradesAvailable] = ALIEN_UPGRADE_CATEGORY_DEFENSE;
this->mNumUpgradesAvailable += 1;
}
}
}
bool AvHHud::GetCommanderLabelText(std::string& outCommanderName) const
{
int theCommander = this->GetCommanderIndex();
bool theHasCommander = (theCommander > 0) && (theCommander <= gEngfuncs.GetMaxClients());
if(!theHasCommander)
{
LocalizeString(kNoCommander, outCommanderName);
return false; // No commander
}
else
{
std::stringstream theStream;
string theCommanderText;
LocalizeString(kCommander, theCommanderText);
theStream << theCommanderText;
theStream << ": ";
hud_player_info_t thePlayerInfo;
gEngfuncs.pfnGetPlayerInfo(theCommander, &thePlayerInfo);
if(thePlayerInfo.name)
{
const int kMaxCommNameLen = 8;
theStream << string(thePlayerInfo.name).substr(0, kMaxCommNameLen);
}
outCommanderName = theStream.str();
return true;
}
}
void AvHHud::UpdateMarineUI(float inCurrentTime)
{
// Find commander label
Label* theCommanderStatusLabel = NULL;
if(this->mMapMode == MAP_MODE_NS)
{
// Add handler for all pending request buttons (this does hotgroups too)
for(int i = 0; i < MESSAGE_LAST; i++)
{
AvHMessageID theMessageID = AvHMessageID(i);
char theComponentName[256];
sprintf(theComponentName, kPendingImpulseSpecifier, (int)theMessageID);
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(theComponentName, theTechImpulsePanel))
{
bool theVisibility = false;
// Do we have any requests pending?
if(this->GetIsInTopDownMode())
{
PendingRequestListType::iterator theIterator;
for(theIterator = this->mPendingRequests.begin(); theIterator != this->mPendingRequests.end(); theIterator++)
{
if(theIterator->first == theMessageID)
{
if(theIterator->second > 0)
{
theVisibility = true;
}
}
}
switch(theMessageID)
{
case GROUP_SELECT_1:
case GROUP_SELECT_2:
case GROUP_SELECT_3:
case GROUP_SELECT_4:
case GROUP_SELECT_5:
case COMMANDER_SELECTALL:
theVisibility = true;
break;
}
}
theTechImpulsePanel->setVisible(theVisibility);
}
}
}
}
void AvHHud::UpdateCountdown(float inCurrentTime)
{
if(this->mCountDownClock != -1)
{
if(inCurrentTime - this->mCountDownClock > this->mLastTickPlayed)
{
// Play tick
this->PlayHUDSound(HUD_SOUND_COUNTDOWN);
this->mLastTickPlayed++;
}
if(this->mLastTickPlayed > this->mNumTicksToPlay)
{
this->AddTooltip(kGameBegun, false);
this->mCountDownClock = -1;
}
}
}
void AvHHud::UpdateHierarchy()
{
// Start the starting point on the map to our local position
this->mOverviewMap.SetMapExtents(this->GetMapName(), this->mMapExtents);
this->mOverviewMap.SetWorldPosition(gPredictedPlayerOrigin[0], gPredictedPlayerOrigin[1]);
if(this->mHierarchy)
{
this->mHierarchy->SetFullScreen(this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER);
}
if(this->mShowMapHierarchy)
{
this->mShowMapHierarchy->SetFullScreen(true);
}
}
string AvHHud::GetNameOfLocation(vec3_t inLocation) const
{
string theLocationName;
AvHSHUGetNameOfLocation(this->mInfoLocationList, inLocation, theLocationName);
return theLocationName;
}
void AvHHud::UpdateInfoLocation()
{
if(this->GetIsAlive() && this->GetHUDUser3() != AVH_USER3_ALIEN_EMBRYO)
{
// Don't clear our location, disconcerting to see our location disappear
//this->mLocationText = "";
this->mLocationText = this->GetNameOfLocation(gPredictedPlayerOrigin);
}
else
{
this->mLocationText = "";
}
}
bool AvHHud::GetIsCombatMode() const
{
return (this->mMapMode == MAP_MODE_CO);
}
bool AvHHud::GetIsNSMode() const
{
return (this->mMapMode == MAP_MODE_NS);
}
bool AvHHud::GetIsMouseInRegion(int inX, int inY, int inWidth, int inHeight)
{
bool theMouseIsInRegion = false;
if(this->GetInTopDownMode())
{
int theMouseX, theMouseY;
this->GetMousePos(theMouseX, theMouseY);
if((theMouseX >= inX) && (theMouseX <= (inX + inWidth)))
{
if((theMouseY >= inY) && (theMouseY <= (inY + inHeight)))
{
theMouseIsInRegion = true;
}
}
}
return theMouseIsInRegion;
}
void AvHHud::TraceEntityID(int& outEntityID)
{
pmtrace_t tr;
vec3_t up, right, forward;
// Trace forward to see if we see a player
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers (-1);
gEngfuncs.pEventAPI->EV_SetTraceHull(2);
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
int theLocalPlayerIndex = theLocalPlayer->index;
//AngleVectors(theLocalPlayer->curstate.angles, forward, right, up);
pVector theRealView;
gEngfuncs.pfnAngleVectors(pmove->angles, forward, right, up);
Vector theStartTrace;
//VectorMA(gPredictedPlayerOrigin, kMaxPlayerHullWidth, forward, theStartTrace);
VectorCopy(gPredictedPlayerOrigin, theStartTrace);
Vector theEndTrace;
VectorMA(gPredictedPlayerOrigin, 8192, forward, theEndTrace);
bool theDone = false;
do
{
gEngfuncs.pEventAPI->EV_PlayerTrace(theStartTrace, theEndTrace, PM_NORMAL, -1, &tr);
// Ignore local player, and ignore the player we're spectating
int theHit = gEngfuncs.pEventAPI->EV_IndexFromTrace(&tr);
if(theHit == theLocalPlayerIndex)
{
VectorMA(tr.endpos, kHitOffsetAmount, forward, theStartTrace);
}
// We hit something
else if(tr.fraction < 1.0)
{
physent_t* pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent );
if(pe)
{
int thePotentialEntity = pe->info;
//if((thePotentialEntity >= 1) && (thePotentialEntity < gEngfuncs.GetMaxClients()))
//{
outEntityID = pe->info;
//}
}
theDone = true;
}
} while(!theDone);
gEngfuncs.pEventAPI->EV_PopPMStates();
}
bool AvHHud::GetAlienHelpForMessage(int inMessageID, string& outHelpText, int& outPointCost) const
{
bool theSuccess = false;
char theNumber[8];
sprintf(theNumber, "%d", inMessageID);
string theNumberString(theNumber);
string theTechHelpText;
string theKey = string(kTechNodeHelpPrefix) + theNumberString;
if(LocalizeString(theKey.c_str(), theTechHelpText))
{
string thePointString;
if(LocalizeString(kPointsSuffix, thePointString))
{
/*
// Lookup point cost
for(UpgradeCostListType::const_iterator theIter = this->mPersonalUpgradeCosts.begin(); theIter != this->mPersonalUpgradeCosts.end(); theIter++)
{
if(theIter->first == inMessageID)
{
char theCostSuffix[128];
sprintf(theCostSuffix, " (%d %s)", theIter->second, thePointString.c_str());
outPointCost = theIter->second;
theTechHelpText += string(theCostSuffix);
outHelpText = theTechHelpText;
theSuccess = true;
break;
}
}
*/
}
}
return theSuccess;
}
bool AvHHud::GetDoesPlayerHaveOrder() const
{
bool thePlayerHasOrder = false;
for(OrderListType::const_iterator theIter = this->mOrders.begin(); theIter != this->mOrders.end(); theIter++)
{
// Draw the order if the order is for any plays that are in our draw player list
EntityInfo theReceiverPlayer = theIter->GetReceiver();
cl_entity_s* thePlayer = gEngfuncs.GetLocalPlayer();
if(thePlayer)
{
int thePlayerIndex = thePlayer->index;
if (thePlayerIndex == theReceiverPlayer )
{
thePlayerHasOrder = true;
break;
}
}
}
return thePlayerHasOrder;
}
bool AvHHud::GetHelpForMessage(int inMessageID, string& outHelpText) const
{
bool theSuccess = false;
char theNumber[8];
sprintf(theNumber, "%d", (int)inMessageID);
string theNumberString(theNumber);
string theKey = string(kTechNodeLabelPrefix) + theNumberString;
string theTechNodeLabel;
if(LocalizeString(theKey.c_str(), theTechNodeLabel))
{
theKey = string(kTechNodeHelpPrefix) + theNumberString;
string theTechNodeHelp;
if(LocalizeString(theKey.c_str(), theTechNodeHelp))
{
outHelpText = /*theTechNodeLabel + " " +*/ theTechNodeLabel;
theSuccess = true;
int theCost;
bool theResearchable;
float theTime;
this->mTechNodes.GetResearchInfo((AvHMessageID)(inMessageID), theResearchable, theCost, theTime);
// Add cost
if(theCost > 0)
{
string theCostString;
if(AvHSHUGetDoesTechCostEnergy((AvHMessageID)inMessageID))
{
LocalizeString(kEnergyPrefix, theCostString);
}
else
{
LocalizeString(kMessageButtonCost, theCostString);
}
outHelpText += " ";
outHelpText += theCostString;
outHelpText += " ";
outHelpText += MakeStringFromInt(theCost);
// Draw description below
//outHelpText += "\n";
//outHelpText += theTechNodeHelp;
}
}
}
return theSuccess;
}
void AvHHud::UpdateMusic(float inCurrentTime)
{
bool theMusicEnabled = false;
if(this->GetGameStarted())
{
// If we're entering play mode and music is enabled, allow playing of music
if(this->GetHUDPlayMode() != PLAYMODE_READYROOM && (cl_musicenabled->value == 1.0f) && (cl_musicvolume->value > 0))
{
theMusicEnabled = true;
}
}
this->SetMusicAllowed(theMusicEnabled);
UIHud::UpdateMusic(inCurrentTime);
}
void AvHHud::UpdatePieMenuControl()
{
// Set which pie menu to use ("" for none)
bool theScoreBoardIsOpen = false;
ScorePanel* theScoreBoard = gViewPort->GetScoreBoard();
if(theScoreBoard && theScoreBoard->isVisible())
{
theScoreBoardIsOpen = true;
}
if(theScoreBoardIsOpen)
{
AvHPieMenuHandler::SetPieMenuControl("");
}
else
{
AvHPieMenuHandler::SetPieMenuControl(this->mPieMenuControl);
}
// Clear all nodes in case VGUI didn't catch events (seems to happen with lag)
if(!gPieMenuHandler.GetIsPieMenuOpen())
{
PieMenu* theCurrentPieMenu = gPieMenuHandler.GetActivePieMenu();
if(theCurrentPieMenu)
{
theCurrentPieMenu->SetFadeState(false);
}
}
// If we're dead, make sure the popup menu is closed
if(!this->GetIsAlive(false))
{
gPieMenuHandler.ClosePieMenu();
}
}
bool AvHHud::GetEntityInfoString(int inEntityID, string& outEntityInfoString, bool& outIsEnemy)
{
bool theSuccess = false;
bool theIsEnemy = false;
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(inEntityID);
if(theEntity)
{
AvHTeamNumber theTeam = this->GetHUDTeam();
if((inEntityID >= 1) && (inEntityID <= gEngfuncs.GetMaxClients()))
{
hud_player_info_t thePlayerInfo;
gEngfuncs.pfnGetPlayerInfo(inEntityID, &thePlayerInfo);
string thePrePendString;
// Don't show cloaked enemies
if((theTeam != TEAM_IND) && !this->GetInTopDownMode() && ((theEntity->curstate.team == theTeam) || (theEntity->curstate.rendermode == kRenderNormal)))
{
//string thePostPendString;
if((theEntity->curstate.team == theTeam))
{
//LocalizeString(kFriendText, thePrePendString);
//sprintf(thePostPendString, " (health: %d)", theEntity->curstate.health);
}
else
{
LocalizeString(kEnemyText, thePrePendString);
theIsEnemy = true;
}
if(thePrePendString != "")
{
outEntityInfoString = thePrePendString + " - ";
}
}
if(thePlayerInfo.name)
{
outEntityInfoString += thePlayerInfo.name;// + thePostPendString;
// Get string from status bar and append it
const char* theStatusCStr = this->m_StatusBar.GetStatusString();
if(strlen(theStatusCStr) > 0)
{
outEntityInfoString += string(theStatusCStr);
}
outIsEnemy = theIsEnemy;
theSuccess = true;
}
// sprintf(thePlayerName, "%s (health: %d)", thePlayerInfo.name, thePlayer->curstate.health);
//}
}
else
{
bool theAutoHelpEnabled = gEngfuncs.pfnGetCvarFloat(kvAutoHelp);
// Return the type of thing it is
AvHUser3 theUser3 = (AvHUser3)(theEntity->curstate.iuser3);
if(this->GetTranslatedUser3Name(theUser3, outEntityInfoString))
{
if((theEntity->curstate.team != TEAM_IND) && (theEntity->curstate.team != theTeam))
{
outIsEnemy = true;
}
// Upper case first character
if(outEntityInfoString.length() > 0)
{
int theFirstChar = outEntityInfoString[0];
int theUpperFirstChar = toupper(theFirstChar);
outEntityInfoString[0] = theUpperFirstChar;
}
// Assume status bar set to health/armor/info data
const char* theStatusCStr = this->m_StatusBar.GetStatusString();
bool theHasStatusString = (strlen(theStatusCStr) > 0);
if(theHasStatusString)
{
outEntityInfoString += string(theStatusCStr);
}
if(theAutoHelpEnabled)
{
string theDescription;
bool theIsFriendly = (this->GetHUDTeam() == theEntity->curstate.team);
if(this->GetTranslatedUser3Description(theUser3, theIsFriendly, theDescription))
{
outEntityInfoString += " - " + theDescription;
}
}
// Only display help when asked for or important
if(theAutoHelpEnabled || theHasStatusString)
{
theSuccess = true;
}
}
}
}
return theSuccess;
}
void AvHHud::UpdateEntityID(float inCurrentTime)
{
this->mBuildingEffectsEntityList.clear();
bool theSetHelpMessage = false;
bool theSetReticleMessage = false;
//char* theNewPlayerName = NULL;
int theEntityIndex = -1;
if(this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER)
{
int theCurrentX, theCurrentY;
this->GetMousePos(theCurrentX, theCurrentY);
// Don't show help when mouse is over the UI
float theNormX = ((float)theCurrentX)/(ScreenWidth());
float theNormY = ((float)theCurrentY)/(ScreenHeight());
if(!this->GetIsRegionBlockedByUI(theNormX, theNormY))
{
Vector theNormRay;
CreatePickingRay(theCurrentX, theCurrentY, theNormRay);
// Look for player and entities under/near the mouse
AvHSHUGetEntityAtRay(this->GetVisualOrigin(), theNormRay, theEntityIndex);
}
}
else if(g_iUser1 != OBS_IN_EYE)
{
// Trace entity id in front of us
this->TraceEntityID(theEntityIndex);
}
if(this->mSelectingWeaponID != -1)
{
// Look up help, set our current help to it
string theWeaponHelpKey;
sprintf(theWeaponHelpKey, kWeaponHelpText, this->mSelectingWeaponID);
string theHelpText;
if(LocalizeString(theWeaponHelpKey.c_str(), theHelpText))
{
// Get damage amount from weapon
ASSERT(this->mSelectingWeaponID >= 0);
ASSERT(this->mSelectingWeaponID < 32);
WEAPON* theWeapon = gWR.GetWeapon(this->mSelectingWeaponID);
if( theWeapon )
{
int theDamage = theWeapon->iMax2;
char theHelpTextWithDamage[1024];
sprintf(theHelpTextWithDamage, theHelpText.c_str(), theDamage);
this->SetHelpMessage(theHelpTextWithDamage);
theSetHelpMessage = true;
}
}
}
else if(this->mTechHelpText != "")
{
this->SetHelpMessage(this->mTechHelpText, false, .8f, .6f);
theSetHelpMessage = true;
}
else if(this->mSelectingNodeID > 0)
{
char theNumber[8];
sprintf(theNumber, "%d", this->mSelectingNodeID);
string theNumberString(theNumber);
string theKey = string(kTechNodeHelpPrefix) + theNumberString;
if(LocalizeString(theKey.c_str(), this->mReticleInfoText))
{
string theCostString;
if(LocalizeString(kCostMarker, theCostString))
{
string thePointsString;
if(LocalizeString(kPointsSuffix, thePointsString))
{
}
// Don't draw marine sayings, as they are printed on the controls and the aliens are using the titles.txt entries
if(this->GetIsMarine())
{
switch(this->mSelectingNodeID)
{
case SAYING_1:
case SAYING_2:
case SAYING_3:
case SAYING_4:
case SAYING_5:
case SAYING_6:
case SAYING_7:
case SAYING_8:
case SAYING_9:
this->mReticleInfoText = "";
break;
}
}
this->SetHelpMessage(this->mReticleInfoText);
theSetHelpMessage = true;
}
}
}
if(theEntityIndex > 0)
{
// Don't draw info for cloaked structures
cl_entity_s* theProgressEntity = gEngfuncs.GetEntityByIndex(theEntityIndex);
if(theProgressEntity)
{
if((theProgressEntity->curstate.rendermode != kRenderTransTexture) || (theProgressEntity->curstate.renderamt > kAlienStructureCloakAmount))
{
if(std::find(this->mBuildingEffectsEntityList.begin(), this->mBuildingEffectsEntityList.end(), theEntityIndex) == this->mBuildingEffectsEntityList.end())
{
this->mBuildingEffectsEntityList.push_back(theEntityIndex);
}
bool theEntityIsPlayer = ((theEntityIndex > 0) && (theEntityIndex <= gEngfuncs.GetMaxClients()));
string theHelpText;
bool theIsEnemy = false;
if(this->GetEntityInfoString(theEntityIndex, theHelpText, theIsEnemy))
{
// Set color to red if enemy, otherise to our HUD color
int theR, theG, theB;
if(theIsEnemy)
{
theR = 255;
theG = theB = 0;
}
else
{
this->GetPrimaryHudColor(theR, theG, theB, true, false);
}
// If we have auto help on, or we're in top down mode, display as help
if(gEngfuncs.pfnGetCvarFloat(kvAutoHelp) || this->GetInTopDownMode())
{
this->SetHelpMessage(theHelpText);
this->mHelpMessage.SetRGB(theR, theG, theB);
theSetHelpMessage = true;
}
// else, display as reticle message
else
{
this->SetReticleMessage(theHelpText);
this->mReticleMessage.SetRGB(theR, theG, theB);
theSetReticleMessage = true;
}
}
}
else
{
//char theMessage[128];
//sprintf(theMessage, "Entity %d cloaked, not drawing circle.", theProgressEntity->curstate.iuser3);
//CenterPrint(theMessage);
}
}
}
float theTimePassed = (inCurrentTime - this->mTimeOfLastUpdate);
if(!theSetHelpMessage)
{
this->mHelpMessage.FadeText(theTimePassed, true);
}
if(!theSetReticleMessage)
{
this->mReticleMessage.FadeText(theTimePassed, true);
}
}
int AvHHud::GetMenuTechSlots() const
{
return this->mMenuTechSlots;
}
const AvHTechTree& AvHHud::GetTechNodes() const
{
return this->mTechNodes;
}
void AvHHud::GetTooltipDrawingInfo(float& outNormX, float& outNormY) const
{
outNormX = kHelpMessageLeftEdgeInset;
outNormY = kHelpMessageTopEdgeInset;
if(this->GetPlayMode() == PLAYMODE_READYROOM)
{
outNormY = 1.0f;
}
else if(this->GetInTopDownMode())
{
outNormY = kHelpMessageCommanderTopEdgeInset;
}
else if(this->GetIsAlien())
{
outNormY = kHelpMessageAlienTopEdgeInset;
}
outNormY -= kToolTipVerticalSpacing;
}
string AvHHud::GetRankTitle(bool inShowUnspentLevels) const
{
string theText;
char* theTeamName = this->GetIsMarine() ? "Marine" : "Alien";
int theCurrentLevel = this->GetHUDExperienceLevel();
char theCharArray[512];
sprintf(theCharArray, kRankText, theTeamName, theCurrentLevel);
LocalizeString(theCharArray, theText);
// Add unspent levels, if any
int theUnspentLevels = (this->mExperienceLevel - this->mExperienceLevelSpent - 1);
if(inShowUnspentLevels && (theUnspentLevels > 0))
{
// We can't accurately draw player's unspent levels when we're dead, as we only know our own
if(this->GetIsAlive(false))
{
string theUnspentLevelText = "(+" + MakeStringFromInt(theUnspentLevels) + ")";
theText += theUnspentLevelText;
}
}
return theText;
}
void AvHHud::GetReticleTextDrawingInfo(float& outNormX, float& outNormY, bool& outCentered) const
{
outCentered = false;
if(this->GetInTopDownMode())
{
int theCurrentX, theCurrentY;
this->GetMousePos(theCurrentX, theCurrentY);
outNormX = theCurrentX/(float)ScreenWidth();
outNormY = theCurrentY/(float)ScreenHeight();
// Move text up a bit so it doesn't obscure
outNormY -= .1f;
outCentered = true;
}
else
{
if(gEngfuncs.pfnGetCvarFloat(kvCenterEntityID))
{
outNormX = .5f;
outNormY = .5f;
outCentered = true;
}
else
{
outNormX = kHelpMessageLeftEdgeInset;
outNormY = kHelpMessageTopEdgeInset - kReticleMessageHeight;
// Alien HUD forces this to be inset a bit
if(this->GetIsAlien())
{
outNormX = kHelpMessageAlienLeftedgeInset + kReticleMessageAlienLeftInset;
outNormY = kHelpMessageAlienTopEdgeInset - kReticleMessageHeight;
}
}
}
}
// Assumes that the tooltips aren't centered
void AvHHud::UpdateTooltips(float inCurrentTime)
{
float theReticleX;
float theReticleY;
this->GetTooltipDrawingInfo(theReticleX, theReticleY);
float theBottomMostY = theReticleY;
float theTimePassed = inCurrentTime - this->mTimeOfLastUpdate;
float kMovement = 1.0f*theTimePassed;
int theBottomScreenY = theBottomMostY*ScreenHeight();
// Clear all tooltips on a role change, or on a playmode change
AvHUser3 theCurrentUser3 = this->GetHUDUser3();
AvHTeamNumber theCurrentTeam = this->GetHUDTeam();
AvHPlayMode thePlayMode = this->GetPlayMode();
if((theCurrentUser3 != this->mLastUser3) || (this->mLastTeamNumber != theCurrentTeam) || ((thePlayMode != this->mLastPlayMode) && (this->mLastPlayMode != PLAYMODE_UNDEFINED)) )
{
this->mTooltips.clear();
}
// Stuff to get reset on a team change
if(this->mLastTeamNumber != theCurrentTeam)
{
this->mExperienceLevelLastDrawn = 1;
}
// Run through list, dropping them down as far as they can go. Assumes the first one in the list is the bottommost one
for(AvHTooltipListType::iterator theIter = this->mTooltips.begin(); theIter != this->mTooltips.end(); /* no inc */)
{
// Recompute settings, if it hasn't been updated before
theIter->RecomputeIfNeccessary();
// Get height of current tool tip
int theTooltipScreenHeight = theIter->GetScreenHeight();
// Move it down towards the current limit
float theCurrentMinScreenY = theIter->GetNormalizedScreenY();
int theCurrentTipScreenBottom = (int)(theCurrentMinScreenY) + theTooltipScreenHeight;
float theCurrentMaxNormY = (float)(theBottomScreenY - theTooltipScreenHeight)/ScreenHeight();
float theNewNormY = min(theCurrentMaxNormY, (theCurrentMinScreenY + kMovement));
// Now this is a crazy bug! In release mode without the following two statements, theNewNormY isn't > theCurrentMinScreenY when it should be.
// It's as if a little time is needed between the computation of theNewNormY and using theNewNormY for it to work
char theMessage[256];
sprintf(theMessage, "theNewNormY %f, minScreenY: %f)", theNewNormY, theCurrentMinScreenY);
//CenterPrint(theMessage);
// If we moved it down
if(theNewNormY > theCurrentMinScreenY)
{
// Fade it in while it's dropping
theIter->FadeText(theTimePassed, false);
}
else
{
if(theIter == this->mTooltips.begin())
{
// If it's at the bottom of the list, start fading it out
theIter->FadeText(theTimePassed, true);
}
}
// Set the new position
theIter->SetNormalizedScreenY(theNewNormY);
// Subtract it's height to the current limit
theBottomScreenY -= theTooltipScreenHeight;
// Subtract out small spacing amount
theBottomScreenY -= max(1, kToolTipVerticalSpacing*ScreenHeight());
// If it's totally faded out, remove it from the list, else process next
int theAlpha = theIter->GetA();
if(theAlpha == 0)
{
theIter = this->mTooltips.erase(theIter);
}
else
{
theIter++;
}
//char theTempBuffer[256];
//sprintf(theTempBuffer, "UpdateTooltips, alpha: %d\n", theAlpha);
//CenterPrint(theTempBuffer);
}
// Update combat upgrade menu too
if(this->GetIsCombatMode())
{
const int kScrollDirection = this->mDrawCombatUpgradeMenu ? 1 : -1;
const float kScrollingSpeed = .7f*kScrollDirection;
float theXDiff = (theTimePassed*kScrollingSpeed);
const float kNormalizedWidth = this->mCombatUpgradeMenu.GetNormalizedMaxWidth();
const float kLeftEdgeInset = .02f;
float theNewX = this->mCombatUpgradeMenu.GetNormalizedScreenX() + theXDiff;
theNewX = max(-kNormalizedWidth, theNewX);
theNewX = min(theNewX, kLeftEdgeInset);
this->mCombatUpgradeMenu.SetNormalizedScreenX(theNewX);
}
}
void AvHHud::UpdateStructureNotification(float inCurrentTime)
{
const float kTimeToDisplayIcon = 6.0f;
const int kMaxIcons = 5;
for(StructureHUDNotificationListType::iterator theIter = this->mStructureNotificationList.begin(); theIter != this->mStructureNotificationList.end(); /* no inc */)
{
if((inCurrentTime > (theIter->mTime + kTimeToDisplayIcon)) || (this->mStructureNotificationList.size() > kMaxIcons))
{
theIter = this->mStructureNotificationList.erase(theIter);
}
else
{
theIter++;
}
}
}
//void AvHHud::FadeText(float inCurrentTime, bool inFadeDown)
//{
// const float kReticleInfoFadeUpSpeed = 500;
// const float kReticleInfoFadeDownSpeed = -150;
//
// // Fade reticle nicely
// int theFadeSpeed = inFadeDown ? kReticleInfoFadeDownSpeed : kReticleInfoFadeUpSpeed;
//
// float theTimePassed = (inCurrentTime - this->mTimeOfLastUpdate);
// float theNewAlpha = this->mReticleInfoColorA + theTimePassed*theFadeSpeed;
// this->mReticleInfoColorA = max(0, min(255, theNewAlpha));
//}
float AvHHud::GetTimeOfLastUpdate() const
{
return this->mTimeOfLastUpdate;
}
void AvHHud::UpdateProgressBar()
{
this->HideProgressStatus();
float thePercentage;
if(gMiniMap.GetIsProcessing(&thePercentage))
{
if(gMiniMap.WriteSpritesIfJustFinished())
{
this->HideProgressStatus();
}
else
{
this->SetProgressStatus(thePercentage);
}
}
// else if(this->mProgressBarEntityIndex == -1)
// {
// this->HideGenericProgressStatus();
// }
else
{
// Look up entity, and set progress according to it's fuser1
cl_entity_s* theProgressEntity = gEngfuncs.GetEntityByIndex(this->mProgressBarEntityIndex);
if(theProgressEntity)
{
ASSERT(this->mProgressBarParam >= 1);
ASSERT(this->mProgressBarParam <= 4);
float theProgress = 0.0f;
switch(this->mProgressBarParam)
{
case 1:
theProgress = theProgressEntity->curstate.fuser1;
break;
case 2:
theProgress = theProgressEntity->curstate.fuser2;
break;
case 3:
theProgress = theProgressEntity->curstate.fuser3;
break;
case 4: // NOTE: check delta.lst for fuser4, it isn't propagated currently
theProgress = theProgressEntity->curstate.fuser4;
break;
}
if((this->GetHUDUser3() == AVH_USER3_ALIEN_EMBRYO) || this->GetIsDigesting())
{
theProgress = pmove->fuser3;
}
thePercentage = theProgress/kNormalizationNetworkFactor;
if(thePercentage < 1.0f)
{
this->SetProgressStatus(thePercentage);
}
// else
// {
// this->HideGenericProgressStatus();
// }
}
else
{
// Look at selection. If selection has research and research isn't done, draw research bar. Else, hide research bar
if(this->mSelected.size() == 1)
{
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(*this->mSelected.begin());
if(theEntity)
{
this->HideProgressStatus();
this->HideResearchProgressStatus();
bool theIsBuilding, theIsResearching;
float thePercentage;
AvHSHUGetBuildResearchState(theEntity->curstate.iuser3, theEntity->curstate.iuser4, theEntity->curstate.fuser1, theIsBuilding, theIsResearching, thePercentage);
if(theIsBuilding && (thePercentage > 0.0f) && (thePercentage < 1.0f))
{
// Turned off progress bar now that we have circular build icons
//this->SetGenericProgressStatus(thePercentage);
}
else if(theIsResearching && (thePercentage > 0) && (thePercentage < 1.0f))
{
this->SetResearchProgressStatus(thePercentage);
}
}
}
}
}
}
void AvHHud::GhostBuildingCallback(struct tempent_s* inEntity, float inFrametime, float inCurrentTime)
{
if(this->mGhostBuilding != MESSAGE_NULL)
{
// Don't let it die
inEntity->die = gClientTimeLastUpdate + 2.0f;
// Update position to be where mouse is
VectorCopy(this->mGhostWorldLocation, inEntity->entity.origin);
// Visually indicate whether this is a valid position or not
if(this->mCurrentGhostIsValid)
{
inEntity->entity.curstate.renderfx = kRenderFxGlowShell;
inEntity->entity.curstate.rendercolor.r = 0;
inEntity->entity.curstate.rendercolor.g = 255;
inEntity->entity.curstate.rendercolor.b = 0;
inEntity->entity.curstate.renderamt = kShellRenderAmount;
}
else
{
inEntity->entity.curstate.renderfx = kRenderFxGlowShell;
inEntity->entity.curstate.rendercolor.r = 255;
inEntity->entity.curstate.rendercolor.g = 0;
inEntity->entity.curstate.rendercolor.b = 0;
inEntity->entity.curstate.renderamt = kShellRenderAmount;
}
}
else
{
// Kill it off immediately
inEntity->die = gClientTimeLastUpdate;
}
}
void AvHHud::UpdateBuildingPlacement()
{
if(this->mGhostBuilding != MESSAGE_NULL)
{
// Fetch current mouse up/down state from gScrollHandler and store
bool theMouseOneDown = gScrollHandler.GetMouseOneDown() && !gCommanderHandler.GetMouseOneDown();
bool theMouseTwoDown = gScrollHandler.GetMouseTwoDown();
// If we haven't created the temp entity, create it
if(!this->mCreatedGhost)
{
// Create the temporary entity
int theModelIndex;
char* theModelName = AvHSHUGetBuildTechModelName(this->mGhostBuilding);
if(theModelName)
{
if(this->mLastGhostBuilding)
{
this->mLastGhostBuilding->die = -1;
this->mLastGhostBuilding = NULL;
}
vec3_t theOrigin = this->GetVisualOrigin();
struct model_s* theModel = gEngfuncs.CL_LoadModel(theModelName, &theModelIndex);
TEMPENTITY* theTempEntity = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom(gPredictedPlayerOrigin, theModel, 0, CLinkGhostBuildingCallback);
if(theTempEntity)
{
theTempEntity->die += 10.0f;
theTempEntity->flags |= FTENT_PERSIST;
// Temp entities interpret baseline origin as velocity.
VectorCopy(vec3_origin, theTempEntity->entity.baseline.origin);
// Set special properties for some models
if(this->mGhostBuilding == BUILD_SCAN)
{
theTempEntity->entity.curstate.rendermode = kRenderTransAdd;
theTempEntity->entity.curstate.renderamt = 255;
theTempEntity->entity.baseline.rendermode = kRenderTransAdd;
theTempEntity->entity.baseline.renderamt = 255;
}
this->mCreatedGhost = true;
}
this->mLastGhostBuilding = theTempEntity;
}
}
// Update location we draw ghosted entity
int theMouseX, theMouseY;
this->GetMousePos(theMouseX, theMouseY);
Vector theNormMousePos;
CreatePickingRay(theMouseX, theMouseY, theNormMousePos);
//char theMessage[256];
//sprintf(theMessage, "Ghost: %f, %f, %f", this->mGhostWorldLocation[0], this->mGhostWorldLocation[1],this->mGhostWorldLocation[2]);
//CenterPrint(theMessage);
// Was either mouse button pressed?
bool theMouseOneReleased = (theMouseOneDown && !this->mMouseOneDown);
bool theMouseTwoReleased = (theMouseTwoDown && !this->mMouseTwoDown);
if(theMouseOneReleased)
{
VectorCopy(this->mLeftMouseWorldStart, this->mNormBuildLocation);
}
else if(theMouseTwoReleased)
{
VectorCopy(this->mRightMouseWorldStart, this->mNormBuildLocation);
}
// Test to see if we're in a valid position
this->mCurrentGhostIsValid = false;
vec3_t theLocation;
if(AvHSHUTraceAndGetIsSiteValidForBuild(this->mGhostBuilding, this->GetVisualOrigin(), theNormMousePos, &theLocation))
{
// Update with cost and research info
bool theIsResearchable;
int theCost;
float theTime;
if(this->mTechNodes.GetResearchInfo(this->mGhostBuilding, theIsResearchable, theCost, theTime))
{
// Ghost is valid if message available and
// we have enough resources OR
// tech takes energy and we have enough energy
this->mCurrentGhostIsValid = false;
if(this->mTechNodes.GetIsMessageAvailable(this->mGhostBuilding))
{
bool theTakesEnergy = AvHSHUGetDoesTechCostEnergy(this->mGhostBuilding);
if((theCost <= this->mResources) || (theTakesEnergy))
{
this->mCurrentGhostIsValid = true;
}
}
}
}
// Draw at selection start range * invalid range multiplier if invalid placement, draw on at target location if valid
//VectorMA(this->GetVisualOrigin(), kSelectionStartRange*kBuildInvalidRangeMultiplier, theNormMousePos, this->mGhostWorldLocation);
VectorMA(this->GetVisualOrigin(), kSelectionStartRange*8, theNormMousePos, this->mGhostWorldLocation);
//if(this->mCurrentGhostIsValid)
//{
VectorCopy(theLocation, this->mGhostWorldLocation);
//}
if((theMouseOneReleased) || (theMouseTwoReleased))
{
// If this is a valid location
if(this->mCurrentGhostIsValid)
{
// Play sound
this->PlayHUDSound(HUD_SOUND_PLACE_BUILDING);
// Remember it for input to grab
this->mValidatedBuilding = this->mGhostBuilding;
}
}
}
}
void AvHHud::CancelBuilding()
{
SetGhostBuildingMode(MESSAGE_NULL);
this->mValidatedBuilding = MESSAGE_NULL;
}
void AvHHud::UpdateSelection()
{
// Fetch current mouse up/down state from gScrollHandler and store
bool theMouseOneDown = gScrollHandler.GetMouseOneDown() && !gCommanderHandler.GetMouseOneDown();
bool theMouseTwoDown = gScrollHandler.GetMouseTwoDown();
int theCurrentX, theCurrentY;
this->GetMousePos(theCurrentX, theCurrentY);
CreatePickingRay(theCurrentX, theCurrentY, this->mMouseWorldPosition);
//ASSERT(this->mMouseWorldPosition.z < 0.0f);
// Left mouse button //
// If mouse just pressed, set starting point
if(theMouseOneDown && !this->mMouseOneDown)
{
this->mMouseOneStartX = theCurrentX;
this->mMouseOneStartY = theCurrentY;
this->mLeftMouseStarted = true;
//CreatePickingRay(theCurrentX, theCurrentY, this->mLeftMouseWorldStart);
//ASSERT(this->mLeftMouseWorldStart.z < 0.0f);
VectorCopy(this->mMouseWorldPosition, this->mLeftMouseWorldStart);
}
else
{
this->mLeftMouseStarted = false;
}
// If mouse just released, set flag to indicate selection just changed
if(!theMouseOneDown && this->mMouseOneDown)
{
//CreatePickingRay(theCurrentX, theCurrentY, this->mLeftMouseWorldEnd);
//ASSERT(this->mLeftMouseWorldEnd.z < 0.0f);
VectorCopy(this->mMouseWorldPosition, this->mLeftMouseWorldEnd);
//this->mSelectionJustChanged = true;
this->mLeftMouseEnded = true;
}
else
{
this->mLeftMouseEnded = false;
}
// Right mouse button //
// If mouse two just pressed, set starting point
if(theMouseTwoDown && !this->mMouseTwoDown)
{
this->mMouseTwoStartX = theCurrentX;
this->mMouseTwoStartY = theCurrentY;
this->mRightMouseStarted = true;
//CreatePickingRay(theCurrentX, theCurrentY, this->mRightMouseWorldStart);
//ASSERT(this->mRightMouseWorldStart.z < 0.0f);
VectorCopy(this->mMouseWorldPosition, this->mRightMouseWorldStart);
}
else
{
this->mRightMouseStarted = false;
}
// If mouse just released, set flag to indicate selection just changed
if(!theMouseTwoDown && this->mMouseTwoDown)
{
//CreatePickingRay(theCurrentX, theCurrentY, this->mRightMouseWorldEnd);
//ASSERT(this->mRightMouseWorldEnd.z < 0.0f);
VectorCopy(this->mMouseWorldPosition, this->mRightMouseWorldEnd);
//this->mSelectionJustChanged = true;
this->mRightMouseEnded = true;
}
else
{
this->mRightMouseEnded = false;
}
// Set extents of marquee control
this->mSelectionBox->SetStartPos(this->mMouseOneStartX, this->mMouseOneStartY);
this->mSelectionBox->SetEndPos(theCurrentX, theCurrentY);
// Set visibility state of marquee control
//this->mSelectionBox->setVisible(theMouseOneDown);
this->mSelectionBox->setVisible(false);
this->mSelectionBoxX1 = mMouseOneStartX;
this->mSelectionBoxY1 = mMouseOneStartY;
this->mSelectionBoxX2 = theCurrentX;
this->mSelectionBoxY2 = theCurrentY;
this->mSelectionBoxVisible = theMouseOneDown;
// If we're just selecting stuff, don't want to hit this button by mistake
//gCommanderHandler.SetActive(!theMouseOneDown);
// Change context sensitive cursor depending on current position
//if(this->mSelected.size() > 0)
//{
// if(this->mGhostBuilding == MESSAGE_NULL)
// {
// Vector theCurrentMouseRay;
// CreatePickingRay(theCurrentX, theCurrentY, theCurrentMouseRay);
//
// int theTargetIndex;
// AvHOrderTargetType theTargetType;
// Vector theTargetLocation;
// AvHUser3 theUser3 = AVH_USER3_NONE;
// AvHOrderType theOrderType = AvHGetDefaultOrderType(this->GetHUDTeam(), this->GetVisualOrigin(), theCurrentMouseRay, theTargetIndex, theTargetLocation, theUser3, theTargetType);
// Test UI blocking
// theOrderType = ORDERTYPEL_DEFAULT;
// if(!AvHSHUGetIsRegionBlockedByUI((float)theCurrentX/ScreenWidth, (float)theCurrentY/ScreenHeight))
// {
// theOrderType = ORDERTYPET_GUARD;
// }
// this->SetCursor(theOrderType);
// Change cursor depending on order type
//if(theOrderType != ORDERTYPEL_MOVE && this->mSelected.size() > 0 )
//{
// if(!this->GetIsRegionBlockedByUI(theCurrentX/ScreenWidth(), theCurrentY/ScreenHeight()))
// {
//this->SetCursor(theOrderType);
// }
//}
// }
//}
if(this->mLeftMouseEnded)
{
// Select all units at this click or in this area (but don't select when clicking a building down)
if(!this->mPlacingBuilding)
{
gSelectionHelper.QueueSelection(this->GetVisualOrigin(), this->mLeftMouseWorldStart, this->mLeftMouseWorldEnd, this->GetHUDTeam());
gSelectionHelper.ProcessPendingSelections();
}
}
if(gSelectionHelper.SelectionResultsWaiting())
{
EntityListType theNewSelection;
gSelectionHelper.GetAndClearSelection(theNewSelection);
// this->mNumLocalSelectEvents++;
if(theNewSelection != this->mSelected)
{
this->mSelected = theNewSelection;
this->mSelectionJustChanged = true;
}
this->ClearTrackingEntity();
}
// If selection just changed, make sure we have selection effects for everyone
if(this->mSelectionJustChanged)
{
// Create effects
this->SetSelectionEffects(this->mSelected);
this->PlayHUDSound(HUD_SOUND_SELECT);
gCommanderHandler.SetSelectedUnits(this->mSelected);
// Clear flag
this->mSelectionJustChanged = false;
// // Set default order mode
// if(this->mSelected.size() > 0)
// {
// this->mOrderMode = ORDERTYPEL_DEFAULT;
// }
// else
// {
// this->mOrderMode = ORDERTYPE_UNDEFINED;
// }
}
this->UpdateBuildingPlacement();
// Store current mouse state
this->mMouseOneDown = theMouseOneDown;
this->mMouseTwoDown = theMouseTwoDown;
}
void AvHHud::UpdateBuildResearchText()
{
// Hide unchanging ("unhelpful"?) help text after this amount of time
const float kHelpTextInterval = 2.5f;
if(this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER)
{
Label* theHelpTextLabel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kTechHelpText, theHelpTextLabel))
{
gCommanderHandler.RecalculateBuildResearchText();
// Display build/research text
string theBuildResearchText = gCommanderHandler.GetBuildResearchText();
theHelpTextLabel->setText(theBuildResearchText.c_str());
// Center it
int theWidth, theHeight;
theHelpTextLabel->getTextSize(theWidth, theHeight);
int theX, theY;
theHelpTextLabel->getPos(theX, theY);
int theScreenWidth = ScreenWidth();
theHelpTextLabel->setPos(theScreenWidth/2 - theWidth/2, theY);
// Vanish if no text (but keep build/research text visible)
theHelpTextLabel->setVisible(true);
if(theBuildResearchText.length() == 0)// || ((this->mTimeLastHelpTextChanged != -1) && (this->mTimeLastHelpTextChanged + kHelpTextInterval < this->mTimeOfLastUpdate)))
{
theHelpTextLabel->setVisible(false);
}
// Display action button tool tip
string theTechHelpText = gCommanderHandler.GetTechHelpText();
if(theTechHelpText != "")
{
this->SetActionButtonHelpMessage(theTechHelpText);
}
if(theTechHelpText != this->mPreviousHelpText)
{
this->mTimeLastHelpTextChanged = this->mTimeOfLastUpdate;
}
this->mPreviousHelpText = theTechHelpText;
}
}
}
void AvHHud::UpdateTechNodes()
{
this->UpdateBuildResearchText();
// Don't get new node until existing one has been processed
if(this->mTechEvent == MESSAGE_NULL)
{
//if(this->mGameStarted)
//{
//AvHTechNode theTechNode;
//if(gCommanderHandler.GetAndClearTechNodePressed(theTechNode))
AvHMessageID theMessageID;
if(gCommanderHandler.GetAndClearTechNodePressed(theMessageID))
{
// Check for grouping and request events and handle separately
if(this->mTechNodes.GetIsMessageAvailable(theMessageID))
{
bool theIsResearchable;
int theCost;
float theTime;
if(this->mTechNodes.GetResearchInfo(theMessageID, theIsResearchable, theCost, theTime))
{
if(AvHSHUGetIsBuildTech(theMessageID))
{
// Don't check for enough points yet, they might get enough points before they put it down
// Get ready to build it, don't send a research message
this->SetGhostBuildingMode(theMessageID);
}
else if(AvHSHUGetIsResearchTech(theMessageID) && theIsResearchable)
{
// If we hit cancel, and we're in building mode, get out of build mode and throw event away
if((theMessageID == MESSAGE_CANCEL) && (this->GetGhostBuilding() != MESSAGE_NULL))
{
CancelBuilding();
}
else if(theCost <= this->mResources)
{
this->mTechEvent = theMessageID;
}
else
{
// Emit error message that you don't have the resources
this->PlayHUDSound(HUD_SOUND_MARINE_MORE);
}
}
else if(theMessageID == BUILD_RECYCLE)
{
this->mTechEvent = theMessageID;
}
}
else
{
this->mTechEvent = theMessageID;
}
}
else if((theMessageID >= SAYING_1) && (theMessageID <= SAYING_9))
{
this->mTechEvent = theMessageID;
}
}
//}
}
}
void AvHHud::UpdateAmbientSounds()
{
Vector theListenerPosition;
VectorCopy(gPredictedPlayerOrigin, theListenerPosition);
// Commanders have a different PAS then themselves
if(this->mInTopDownMode)
{
VectorCopy(this->mCommanderPAS, theListenerPosition);
}
for(AmbientSoundListType::iterator theIter = this->mAmbientSounds.begin(); theIter != this->mAmbientSounds.end(); theIter++)
{
theIter->StartPlayingIfNot();
theIter->UpdateVolume(theListenerPosition);
}
}
void AvHHud::UpdateFromEntities(float inCurrentTime)
{
// Only update every so often for performance reasons
const float kEntityUpdateInterval = .4f;
if(inCurrentTime > (this->mTimeOfLastEntityUpdate + kEntityUpdateInterval))
{
this->mHelpIcons.clear();
this->mHelpEnts.clear();
bool theAutoHelpEnabled = gEngfuncs.pfnGetCvarFloat(kvAutoHelp);
// Clear help icons
this->mHelpEnts.clear();
// Clear building effects
//this->mBuildingEffectsEntityList.clear();
this->mTimeOfLastEntityUpdate = inCurrentTime;
// Scan for entities, adding help icons
// Only draw if enabled
const int kHelpDistance = 350;
const int kBuildDistance = 500;
const int kHealthDistance = 125;
// Look for entities that have help icons in front of us. Don't search to far away, it could give players away.
EntityListType theHelpEntities;
AvHSHUGetEntities(-1, theHelpEntities);
cl_entity_t* theLocalPlayer = gEngfuncs.GetLocalPlayer();
for(EntityListType::iterator theIter = theHelpEntities.begin(); theIter != theHelpEntities.end(); theIter++)
{
vec3_t theLocation;
if(AvHSHUGetEntityLocation(*theIter, theLocation))
{
float theDistance = VectorDistance((float*)&theLocation, theLocalPlayer->origin);
if(theDistance < kHelpDistance)
{
// If iuser3 isn't 0, try looking up an icon for it
physent_t* theEntity = gEngfuncs.pEventAPI->EV_GetPhysent(*theIter);
if(theEntity)
{
// Don't add cloaked entities (I wish this could be more general purpose)
if((theEntity->team == this->GetHUDTeam()) || (theEntity->rendermode == kRenderNormal))
{
int theUser3 = theEntity->iuser3;
vec3_t theEntityOrigin = AvHSHUGetRealLocation(theEntity->origin, theEntity->mins, theEntity->maxs);
// Some entities always draw
bool theAlwaysDraw = false;
switch(theUser3)
{
case AVH_USER3_WELD:
//case AVH_USER3_COMMANDER_STATION:
//case AVH_USER3_HIVE:
theAlwaysDraw = true;
break;
}
if(theAutoHelpEnabled || theAlwaysDraw)
{
this->mHelpIcons.push_back( make_pair(theEntityOrigin, theUser3) );
// Push back entity for displaying helpful tooltips
this->mHelpEnts.push_back(*theIter);
}
}
}
}
}
}
}
}
void AvHHud::UpdateViewModelEffects()
{
cl_entity_t* theViewModel = GetViewEntity();
if(theViewModel)
{
int theRenderMode = kRenderNormal;
int theRenderAmount = 0;
int theRenderFx = theViewModel->curstate.renderfx;
color24 theRenderColor = theViewModel->curstate.rendercolor;
short theSkin = 0;
// Set the skin, stored in playerclass
//cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
// Use the visible player so that when we are spectating we can tell
// when the player is cloaked.
cl_entity_s* theLocalPlayer = GetVisiblePlayer();
if(theLocalPlayer)
{
//theViewModel->curstate.skin = theLocalPlayer->curstate.skin;
theRenderMode = theLocalPlayer->curstate.rendermode;
theRenderAmount = theLocalPlayer->curstate.renderamt;
theRenderFx = theLocalPlayer->curstate.renderfx;
theRenderColor = theLocalPlayer->curstate.rendercolor;
theSkin = theLocalPlayer->curstate.skin;
// Hack to make cloaking work for viewmodels (if only view models rendered in additive properly).
// Draw view model normally unless fully cloaked.
//bool theIsCloakedViaUpgrade = GetHasUpgrade(theLocalPlayer->curstate.iuser4, MASK_ALIEN_CLOAKED);
int old=theRenderAmount;
if((theRenderMode == kRenderTransTexture) /*|| theIsCloakedViaUpgrade*/)
{
theRenderFx = kRenderFxNone;
theRenderColor.r = theRenderColor.g = theRenderColor.b = 0;
if ( theRenderAmount == kAlienSelfCloakingBaseOpacity )
{
theRenderMode = kAlienCloakViewModelRenderMode;
theRenderAmount = 10;
}
else if( theRenderAmount > kAlienSelfCloakingBaseOpacity && theRenderAmount < 186)
{
theRenderMode = kAlienCloakViewModelRenderMode;
theRenderAmount = 40;
}
else if ( theRenderAmount == 186 ) {
theRenderMode = kAlienCloakViewModelRenderMode;
theRenderAmount = 50;
}
else
{
theRenderMode = kRenderNormal;
theRenderAmount = 255;
}
}
//char theMessage[128];
//sprintf(theMessage, "Setting view model mode: %d amount: %d\n", theRenderMode, theRenderAmount);
//CenterPrint(theMessage);
}
// if(GetHasUpgrade(this->GetLocalUpgrades(), MASK_ALIEN_CLOAKED))
// {
// theRenderMode = kAlienCloakViewModelRenderMode;
// int theCloakingLevel = AvHGetAlienUpgradeLevel(this->GetLocalUpgrades(), MASK_UPGRADE_7);
// theRenderAmount = kAlienCloakViewModelAmount - theCloakingLevel*kAlienCloakViewModelLevelAmount;
//
// // Put in color, because texture rendering needs it
// theRenderFx = kRenderFxNone;
// theRenderColor.r = theRenderColor.g = theRenderColor.b = 0;
// }
if(this->mInTopDownMode)
{
theRenderMode = kRenderTransAdd;
theRenderAmount = 1;
}
theViewModel->curstate.skin = theSkin;
theViewModel->curstate.rendermode = theRenderMode;
theViewModel->curstate.renderamt = theRenderAmount;
theViewModel->curstate.renderfx = theRenderFx;
theViewModel->curstate.rendercolor = theRenderColor;
}
}
void AvHHud::UpdateResources(float inTimePassed)
{
const float kResourceRate = this->GetMaxAlienResources()/50.0f;
int thePointsToMove = max(inTimePassed*kResourceRate, 1);
// Update visual resources if different this resources
if(this->mVisualResources != this->mResources)
{
if(abs(this->mVisualResources - this->mResources) <= thePointsToMove)
{
this->mVisualResources = this->mResources;
}
else
{
if(this->mVisualResources < this->mResources)
{
this->mVisualResources += thePointsToMove;
}
else
{
this->mVisualResources -= thePointsToMove;
}
}
}
// Smoothly adjust energy level
float theCurrentEnergyLevel = pmove->fuser3/kNormalizationNetworkFactor;
if((g_iUser1 == OBS_IN_EYE) && (g_iUser2 != this->mUser2OfLastEnergyLevel))
{
// This isn't working yet
this->mVisualEnergyLevel = theCurrentEnergyLevel;
this->mUser2OfLastEnergyLevel = g_iUser2;
}
else
{
float kEnergyRate = 1.0f;
float theEnergyToMove = inTimePassed*kEnergyRate;
if(this->mVisualEnergyLevel != theCurrentEnergyLevel)
{
float theDiff = fabs(this->mVisualEnergyLevel - theCurrentEnergyLevel);
if(theDiff <= theEnergyToMove)
{
this->mVisualEnergyLevel = theCurrentEnergyLevel;
}
else
{
if(this->mVisualEnergyLevel < theCurrentEnergyLevel)
{
this->mVisualEnergyLevel += theEnergyToMove;
}
else
{
this->mVisualEnergyLevel -= theEnergyToMove;
}
}
}
}
string theResourceText;
char theResourceBuffer[64];
if(this->GetInTopDownMode() && this->mCommanderResourceLabel)
{
LocalizeString(kMarineResourcePrefix, theResourceText);
sprintf(theResourceBuffer, "%s %d", theResourceText.c_str(), this->mVisualResources);
this->mCommanderResourceLabel->setText(64, theResourceBuffer);
}
// Update visual resource indicators, expiring old ones
const float kNumericalInfoEffectLifetime = 1.1f;
const float kNumericalInfoScrollSpeed = 24;
for(NumericalInfoEffectListType::iterator theIter = this->mNumericalInfoEffects.begin(); theIter != this->mNumericalInfoEffects.end(); /* no inc */)
{
if((theIter->GetTimeCreated() + kNumericalInfoEffectLifetime) < this->mTimeOfLastUpdate)
{
theIter = this->mNumericalInfoEffects.erase(theIter);
}
else
{
// Update position
float thePosition[3];
theIter->GetPosition(thePosition);
thePosition[2] += inTimePassed*kNumericalInfoScrollSpeed;
theIter->SetPosition(thePosition);
// Next
theIter++;
}
}
}
//void AvHHud::ChangeUpgradeCosts(int inOldMessageID, int inNewMessageID, const char* inText)
//{
// this->ChangeUpgradeCostsForMenu(this->mSoldierMenu, inOldMessageID, inNewMessageID, inText);
// this->ChangeUpgradeCostsForMenu(this->mLeaderMenu, inOldMessageID, inNewMessageID, inText);
// this->ChangeUpgradeCostsForMenu(this->mCommanderMenu, inOldMessageID, inNewMessageID, inText);
//
// this->UpdateUpgradeCosts();
//}
//
//void AvHHud::ChangeUpgradeCostsForMenu(PieMenu* inMenu, int inOldMessageID, int inNewMessageID, const char* inText)
//{
// if(inMenu)
// {
// inMenu->ChangeNode(inOldMessageID, inNewMessageID, string(inText));
// }
//}
//
//void AvHHud::ResetUpgradeCosts()
//{
// this->ResetUpgradeCostsForMenu(this->mSoldierMenu);
// this->ResetUpgradeCostsForMenu(this->mLeaderMenu);
// this->ResetUpgradeCostsForMenu(this->mCommanderMenu);
//
// this->UpdateUpgradeCosts();
//}
//void AvHHud::ResetUpgradeCostsForMenu(PieMenu* inMenu)
//{
// if(inMenu)
// {
// inMenu->ResetToDefaults();
// }
//}
bool AvHHud::GetParticlesVisible() const
{
if (g_iUser1 == OBS_NONE)
{
return true;
}
if (m_Spectator.IsInOverviewMode())
{
return m_Spectator.m_iDrawCycle == 1;
}
else
{
return true;
}
}
// Sprite drawing on a level change is problematic and can cause crashing or disconcerting "no such sprite" error messages
bool AvHHud::GetSafeForSpriteDrawing() const
{
bool theSafeForDrawing = false;
const char* theLevelName = gEngfuncs.pfnGetLevelName();
string theCurrentMapName = this->GetMapName(true);
if(theLevelName && (theCurrentMapName != ""))
{
string theLevelNameString(theLevelName);
int thePos = (int)theLevelNameString.find(theCurrentMapName);
if(thePos != string::npos)
{
theSafeForDrawing = true;
}
}
return theSafeForDrawing;
}
bool AvHHud::GetShouldDisplayUser3(AvHUser3 inUser3) const
{
bool theShouldDisplay = false;
if((inUser3 > AVH_USER3_NONE) && (inUser3 < AVH_USER3_MAX))
{
theShouldDisplay = true;
switch(inUser3)
{
case AVH_USER3_BREAKABLE:
case AVH_USER3_USEABLE:
case AVH_USER3_PARTICLE_ON:
case AVH_USER3_PARTICLE_OFF:
case AVH_USER3_ALPHA:
case AVH_USER3_WAYPOINT:
case AVH_USER3_NOBUILD:
case AVH_USER3_SPAWN_TEAMA:
case AVH_USER3_SPAWN_TEAMB:
theShouldDisplay = false;
break;
}
}
return theShouldDisplay;
}
bool AvHHud::GetTranslatedUser3Name(AvHUser3 inUser3, string& outString) const
{
bool theSuccess = false;
if(this->GetShouldDisplayUser3(inUser3))
{
char theUser3String[512];
sprintf(theUser3String, "#%s%d", kUser3Name, inUser3);
theSuccess = LocalizeString(theUser3String, outString);
}
return theSuccess;
}
bool AvHHud::GetTranslatedUser3Description(AvHUser3 inUser3, bool inFriendly, string& outString) const
{
bool theSuccess = false;
if(this->GetShouldDisplayUser3(inUser3))
{
char theUser3String[512];
sprintf(theUser3String, "#%s%d", kUser3Description, inUser3);
theSuccess = LocalizeString(theUser3String, outString);
// If we're commanding, look for that description if it exists
if(this->GetInTopDownMode())
{
string theCommanderDescription;
sprintf(theUser3String, "#%s%d", kUser3CommanderDescription, inUser3);
if(LocalizeString(theUser3String, theCommanderDescription))
{
outString = theCommanderDescription;
theSuccess = true;
}
}
// Else look for a message that tell us what to do with this thing (assumes we're not commanding though)
else if(inFriendly)
{
string theFriendlyDescription;
sprintf(theUser3String, "#%s%d", kUser3FriendlyDescription, inUser3);
if(LocalizeString(theUser3String, theFriendlyDescription))
{
outString = theFriendlyDescription;
theSuccess = true;
}
}
}
return theSuccess;
}
void AvHHud::UpdateUpgradeCosts()
{
PieMenu* theCurrentMenu = NULL;
if(this->GetManager().GetVGUIComponentNamed(this->mPieMenuControl, theCurrentMenu))
{
this->UpdateEnableState(theCurrentMenu);
}
}
void AvHHud::AddMiniMapAlert(float x, float y)
{
mOverviewMap.AddAlert(x, y);
}
void AvHHud::UpdateEnableState(PieMenu* inMenu)
{
if(inMenu)
{
int thePurchaseLevel = this->GetIsCombatMode() ? max(0, this->mExperienceLevel - this->mExperienceLevelSpent - 1) : this->mResources;
inMenu->UpdateMenuFromTech(this->mTechNodes, thePurchaseLevel);
// if(this->GetIsNSMode())
//{
// Now disable any nodes whose children are all disabled (in NS, only end nodes can be chosen)
//inMenu->DisableNodesWhoseChildrenAreDisabled();
//}
inMenu->RecomputeVisibleSize();
}
}
void AvHHud::ShowMap()
{
if (!sShowMap && gHUD.GetIsNSMode())
{
sShowMap = true;
gHUD.HideCrosshair();
gHUD.GetManager().UnhideComponent(kShowMapHierarchy);
}
}
void AvHHud::HideMap()
{
if (sShowMap)
{
sShowMap = false;
gHUD.GetManager().HideComponent(kShowMapHierarchy);
gHUD.ShowCrosshair();
}
}
void AvHHud::GetSpriteForUser3(AvHUser3 inUser3, int& outSprite, int& outFrame, int& outRenderMode)
{
switch (inUser3)
{
// Marines
case AVH_USER3_WAYPOINT:
outSprite = Safe_SPR_Load(kSmallOrderSprite);
outFrame = 2;
outRenderMode = kRenderTransAdd;
break;
case AVH_USER3_MARINE_PLAYER:
outSprite = Safe_SPR_Load(kMarinePlayersSprite);
outFrame = 0;
break;
case AVH_USER3_HEAVY: // This really means a marine with heavy armor, not a heavy armor object.
outSprite = Safe_SPR_Load(kMarinePlayersSprite);
outFrame = 1;
break;
case AVH_USER3_COMMANDER_STATION:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 5;
break;
case AVH_USER3_TURRET_FACTORY:
case AVH_USER3_ADVANCED_TURRET_FACTORY:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 6;
break;
case AVH_USER3_ARMORY:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 7;
break;
case AVH_USER3_ADVANCED_ARMORY:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 8;
break;
case AVH_USER3_ARMSLAB:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 9;
break;
case AVH_USER3_PROTOTYPE_LAB:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 10;
break;
case AVH_USER3_OBSERVATORY:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 11;
break;
case AVH_USER3_TURRET:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 12;
break;
case AVH_USER3_SIEGETURRET:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 13;
break;
case AVH_USER3_RESTOWER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 14;
break;
case AVH_USER3_INFANTRYPORTAL:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 15;
break;
case AVH_USER3_PHASEGATE:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 16;
break;
// Aliens
case AVH_USER3_DEFENSE_CHAMBER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 17;
break;
case AVH_USER3_MOVEMENT_CHAMBER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 18;
break;
case AVH_USER3_OFFENSE_CHAMBER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 19;
break;
case AVH_USER3_SENSORY_CHAMBER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 20;
break;
case AVH_USER3_ALIENRESTOWER:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 21;
break;
case AVH_USER3_HIVE:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 3;
break;
case AVH_USER3_ALIEN_PLAYER1:
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 0;
break;
case AVH_USER3_ALIEN_PLAYER2:
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 1;
break;
case AVH_USER3_ALIEN_PLAYER3:
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 2;
break;
case AVH_USER3_ALIEN_PLAYER4:
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 3;
break;
case AVH_USER3_ALIEN_PLAYER5:
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 4;
break;
case AVH_USER3_ALIEN_EMBRYO :
outSprite = Safe_SPR_Load(kAlienPlayersSprite);
outFrame = 5;
break;
case AVH_USER3_FUNC_RESOURCE:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 4;
break;
case AVH_USER3_WELD:
outSprite = Safe_SPR_Load(kStructuresSprite);
outFrame = 0;
break;
default:
outSprite = 0;
outFrame = 0;
}
}
int AvHHud::GetCurrentSquad() const
{
return mCurrentSquad;
}
AvHOverviewMap& AvHHud::GetOverviewMap()
{
return mOverviewMap;
}
void AvHHud::ShowCrosshair()
{
++mCrosshairShowCount;
if (mCrosshairShowCount > 0)
{
SetCrosshair(mCrosshairSprite, mCrosshairRect, mCrosshairR, mCrosshairG, mCrosshairB);
}
}
void AvHHud::HideCrosshair()
{
--mCrosshairShowCount;
if (mCrosshairShowCount <= 0)
{
wrect_t nullrect = { 0, 0, 0, 0 };
SetCrosshair(0, nullrect, 0, 0, 0);
}
}
void AvHHud::SetCurrentCrosshair(HSPRITE hspr, wrect_t rc, int r, int g, int b)
{
mCrosshairSprite = hspr;
mCrosshairRect = rc;
mCrosshairR = r;
mCrosshairG = g;
mCrosshairB = b;
if (mCrosshairShowCount > 0)
{
SetCrosshair(mCrosshairSprite, mCrosshairRect, mCrosshairR, mCrosshairG, mCrosshairB);
}
}
void AvHHud::SetViewport(const int inViewport[4])
{
if (!m_Spectator.IsInOverviewMode())
{
mViewport[0] = inViewport[0];
mViewport[1] = inViewport[1];
mViewport[2] = inViewport[2];
mViewport[3] = inViewport[3];
}
else
{
mSpecialViewport[0] = inViewport[0];
mSpecialViewport[1] = inViewport[1];
mSpecialViewport[2] = inViewport[2];
mSpecialViewport[3] = inViewport[3];
mViewport[0] = 0;
mViewport[1] = 0;
mViewport[2] = ScreenWidth();
mViewport[3] = ScreenHeight();
}
}
void AvHHud::GetViewport(int outViewport[4]) const
{
outViewport[0] = mViewport[0];
outViewport[1] = mViewport[1];
outViewport[2] = mViewport[2];
outViewport[3] = mViewport[3];
}
const AvHFont& AvHHud::GetSmallFont() const
{
return mSmallFont;
}
void AvHHud::PlayStream()
{
if(gEngfuncs.Cmd_Argc() <= 1)
{
gEngfuncs.Con_Printf( "usage: playstream <url>\n" );
}
else
{
if ( gEngfuncs.Cmd_Argc() >= 2 )
{
// Read URL
string theURL;
theURL = string("http://") + string(gEngfuncs.Cmd_Argv(1));
string theError;
if(!gHUD.PlayInternetStream(theURL, theError))
{
gHUD.AddTooltip(theError.c_str());
}
}
}
}
void AvHHud::StopStream()
{
gHUD.StopInternetStream();
}
float AvHHud::GetServerVariableFloat(const char* inName) const
{
ServerVariableMapType::const_iterator iterator;
iterator = mServerVariableMap.find(inName);
if ( iterator == mServerVariableMap.end() )
{
return 0;
}
else
{
return atof( iterator->second.c_str() );
}
}
/**
* Prints the call stack when an unhandled exception occurs.
*/
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* pExp)
{
/*
// E-mail the exception log to the programmers.
std::stringstream buffer;
LogException(buffer, pExp);
const char* serverName = "66.111.4.62";
const char* fromAddress = "noreply@overmind.com";
const char* programmerAddress[] =
{
"max_mcguire@yahoo.com",
};
for (int i = 0; i < sizeof(programmerAddress) / sizeof(char*); ++i)
{
SendMail(serverName, fromAddress, fromAddress, programmerAddress[i],
"Exception Log", buffer.str().c_str());
}
*/
AvHHud::ResetGammaAtExit();
return EXCEPTION_EXECUTE_HANDLER;
}
// Added DLL entry point to try to reset gamma properly under VAC
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
// Install a crash handler.
//SetUnhandledExceptionFilter(ExceptionFilter);
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
AvHHud::ResetGammaAtExit();
}
return TRUE;
}