ns/main/source/mod/AvHHudRender.cpp
tankefugl e6db2ee4e5 Mantis 0000988:
O The commander can now see the health for all buildings and marines, even when not selected, as transparent health circles. Health circles for selected buildings and marines are rendered as normal.

git-svn-id: https://unknownworlds.svn.cloudforge.com/ns1@32 67975925-1194-0748-b3d5-c16f83f1a3a1
2005-04-04 01:45:56 +00:00

3995 lines
132 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: All graphical HUD operations
//
// $Workfile: AvHHudRender.cpp $
// $Date: 2002/10/24 21:31:13 $
//
//-------------------------------------------------------------------------------
// $Log: AvHHudRender.cpp,v $
// Revision 1.25 2002/10/24 21:31:13 Flayra
// - Removed some parts of energy drawing (unneeded clutter)
// - New marine HUD artwork (mainhud.spr)
// - Reworked upgrade drawing to only draw one of a type of upgrade (this was the last thing for v1.0, so it's a bit yucky)
//
// Revision 1.24 2002/10/18 22:20:14 Flayra
// - Fixed alien mass crash when a player left the server
//
// Revision 1.23 2002/10/16 00:59:33 Flayra
// - Added titles for umbra and primal scream
// - Don't draw building circles for entities on the other team (not even for commander)
// - Tried drawing building circles for ghost buildings, but it was confusing
//
// Revision 1.22 2002/10/03 18:56:10 Flayra
// - Moved alien energy to fuser3
// - Changed limits for energy and resources
// - Draw order icons centered around order position
// - Don't draw health rings for opposing teams
//
// Revision 1.21 2002/09/25 20:48:37 Flayra
// - Allow more UI to draw when gestating
// - Only draw text for blip closest to reticle
// - Don't draw stuff when dead
// - Changed order blinking
//
// Revision 1.20 2002/09/23 22:19:58 Flayra
// - Added "paralyzed" indicator
// - HUD element repositioning and refactoring
// - Added alien build circles
// - Added visible motion-tracking sprite to marine HUD
// - Removed special siege sprite
//
// Revision 1.19 2002/09/09 19:57:33 Flayra
// - Fixed black edges in D3D
// - Added blinking "webbed" indicator
// - Refactored UI constants
// - Fixed help icons
// - Added hive info indicator
// - Draw more info as spectator
//
// Revision 1.18 2002/08/31 18:01:01 Flayra
// - Work at VALVe
//
// Revision 1.17 2002/08/16 02:38:44 Flayra
// - Draw "webbed" message
// - Draw health for buildings and players
// - Removed old overwatch code
//
// Revision 1.16 2002/08/09 01:03:36 Flayra
// - Started refactoring for moving variable sprite hole drawing into TriAPI
//
// Revision 1.15 2002/08/02 21:56:54 Flayra
// - Added reticle help, new tooltip system and much nicer order drawing! Also changed jetpack label to use font, and refactored some sprite names.
//
// Revision 1.14 2002/07/26 23:05:06 Flayra
// - Generate numerical feedback for damage events
//
// Revision 1.13 2002/07/23 17:09:41 Flayra
// - Add ability to centered, translated strings, visually-smooth energy level, new hive sight info, draw parasited message, draw marine upgrades, new method of drawing alien upgrades (overlapping and offset)
//
// Revision 1.12 2002/07/10 14:42:26 Flayra
// - Removed cl_particleinfo drawing differences
//
// Revision 1.11 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.10 2002/07/01 21:36:23 Flayra
// - Added primal scream effect, added building ranges for ghost buildings, removed outdated code, removed mapping build sprite, call vidinit() on hive sight sprites
//
// Revision 1.9 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.8 2002/06/10 19:57:01 Flayra
// - Allow drawing just a portion of a texture when scaling it, draw team hierarchy for soldiers
//
// Revision 1.7 2002/06/03 16:49:20 Flayra
// - Help sprites moved into one animated sprite
//
// Revision 1.6 2002/05/28 17:49:06 Flayra
// - Hive sight sprite changes
//
// Revision 1.5 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/AvHHud.h"
#include "cl_dll/hud.h"
#include "cl_dll/cl_util.h"
#include "mod/AvHConstants.h"
#include "mod/AvHClientVariables.h"
#include "mod/AvHSpecials.h"
#include "common/cl_entity.h"
#include "mod/AvHTitles.h"
#include "pm_shared/pm_debug.h"
#include "util/MathUtil.h"
#include "common/r_efx.h"
#include "cl_dll/eventscripts.h"
#include "mod/AvHSprites.h"
#include "ui/UIUtil.h"
#include "types.h"
#include <signal.h>
#include "common/com_model.h"
#include "cl_dll/studio_util.h"
#include "cl_dll/r_studioint.h"
#include "mod/AvHMiniMap.h"
#include "mod/AvHActionButtons.h"
#include "util/STLUtil.h"
#include "mod/AvHSharedUtil.h"
#include "common/event_api.h"
#include "mod/AvHScriptManager.h"
#include <p_vector.h>
#include <papi.h>
#include "mod/AvHParticleSystemManager.h"
#include "mod/AvHTeamHierarchy.h"
#include "mod/AvHClientUtil.h"
#include "mod/AvHTooltip.h"
#include "cl_dll/demo.h"
#include "common/demo_api.h"
#include "mod/AvHHudConstants.h"
#include "mod/AvHPlayerUpgrade.h"
#include "mod/AvHCommanderModeHandler.h"
#include "common/ref_params.h"
#include "mod/AvHTechImpulsePanel.h"
#include "mod/AvHServerVariables.h"
#include "mod/AvHSpriteAPI.h"
#include "mod/AvHParticleEditorHandler.h"
#include <list>
void IN_GetMousePos( int *mx, int *my );
// Externs
extern int g_iVisibleMouse;
extern playermove_t* pmove;
extern engine_studio_api_t IEngineStudio;
extern "C" Vector gPredictedPlayerOrigin;
extern vec3_t v_origin;
extern vec3_t v_angles;
//extern vec3_t gPlayerOrigin;
//extern vec3_t gPlayerAngles;
extern ref_params_s* pDemoRefParams;
extern vec3_t gPlaybackViewOrigin;
extern AvHCommanderModeHandler gCommanderHandler;
extern AvHParticleEditorHandler gParticleEditorHandler;
float kD3DErrorValue = 0.01f;
vec3_t GetViewOrigin()
{
vec3_t theOrigin = v_origin;
//cl_entity_t* theViewEntity = gEngfuncs.GetLocalPlayer();//gEngfuncs.GetViewModel();
//if(theViewEntity && /*pDemoRefParams &&*/ gEngfuncs.pDemoAPI->IsPlayingback())
//{
// //theOrigin = pDemoRefParams->vieworg;
// theOrigin = theViewEntity->origin;
//}
if(gEngfuncs.pDemoAPI->IsPlayingback())
{
theOrigin = gPlaybackViewOrigin;
}
return theOrigin;
// return v_origin;
}
void BuildLerpedPoint(float inXPercentage, float inYPercentage, const Vector& inUpperLeft, const Vector& inUpperRight, const Vector& inLowerLeft, Vector& outPoint)
{
ASSERT(inXPercentage >= 0.0f);
ASSERT(inXPercentage <= 1.0f);
ASSERT(inYPercentage >= 0.0f);
ASSERT(inYPercentage <= 1.0f);
Vector theUpperLeftToUpperRight;
VectorSubtract(inUpperRight, inUpperLeft, theUpperLeftToUpperRight);
Vector theUpperLeftToLowerLeft;
VectorSubtract(inLowerLeft, inUpperLeft, theUpperLeftToLowerLeft);
Vector theXComp;
VectorScale(theUpperLeftToUpperRight, inXPercentage, theXComp);
Vector theYComp;
VectorScale(theUpperLeftToLowerLeft, inYPercentage, theYComp);
outPoint = inUpperLeft + theXComp + theYComp;
//float theXPercentage = (outPoint.x - inUpperLeft.x)/(theXComp.x + theYComp.x);
//float theYPercentage = (outPoint.y - inUpperLeft.y)/(theXComp.y + theYComp.y);
}
void CalculatePlaneInfo(const Vector& inUpperLeft, const Vector& inUpperRight, const Vector& inLowerLeft, float& outD, Vector& outPlaneNormal)
{
// Cross two vectors for plane normal
Vector theUpperRightToUpperLeft;
VectorSubtract(inUpperLeft, inUpperRight, theUpperRightToUpperLeft);
theUpperRightToUpperLeft = theUpperRightToUpperLeft.Normalize();
Vector theUpperLeftToLowerLeft;
VectorSubtract(inLowerLeft, inUpperLeft, theUpperLeftToLowerLeft);
theUpperLeftToLowerLeft = theUpperLeftToLowerLeft.Normalize();
// Calculate plane normal
CrossProduct(theUpperRightToUpperLeft, theUpperLeftToLowerLeft, outPlaneNormal);
// Plug in one of the points for D (Ax + By + Cz = -D)
outD = -(outPlaneNormal.x*inUpperLeft.x + outPlaneNormal.y*inUpperLeft.y + outPlaneNormal.z*inUpperLeft.z);
}
void CalculatePointOnPlane(int inXPos, int inYPos, const Vector& inOrigin, const Vector& inPlaneNormal, float inPlaneD, Vector& outPoint)
{
Vector theRay;
CreatePickingRay(inXPos, inYPos, theRay);
// Solve for parametric t
float thePlaneA = inPlaneNormal.x;
float thePlaneB = inPlaneNormal.y;
float thePlaneC = inPlaneNormal.z;
float theT = -(thePlaneA*inOrigin.x + thePlaneB*inOrigin.y + thePlaneC*inOrigin.z + inPlaneD)/(thePlaneA*theRay.x + thePlaneB*theRay.y + thePlaneC*theRay.z);
// Now we have t, solve for the endpoint
outPoint.x = inOrigin.x + theT*theRay.x;
outPoint.y = inOrigin.y + theT*theRay.y;
outPoint.z = inOrigin.z + theT*theRay.z;
}
void ProjectPointFromViewOrigin(int inDistanceToProject, int inScreenX, int inScreenY, Vector& outResult)
{
Vector theRay;
CreatePickingRay(inScreenX, inScreenY, theRay);
// project default distance along picking ray
VectorMA(GetViewOrigin(), inDistanceToProject, theRay, outResult);
}
void AvHHud::DrawTranslatedString(int inX, int inY, const char* inStringToTranslate, bool inCentered, bool inIgnoreUpgrades, bool inTrimExtraInfo)
{
// Translate
string theTranslatedText;
LocalizeString(inStringToTranslate, theTranslatedText);
if(theTranslatedText[0] == '#')
{
theTranslatedText = theTranslatedText.substr(1, theTranslatedText.size());
}
if(inTrimExtraInfo)
{
AvHCUTrimExtraneousLocationText(theTranslatedText);
}
// Draw it
if(theTranslatedText != "")
{
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, inIgnoreUpgrades, false);
char theCharBuffer[512];
sprintf(theCharBuffer, "%s", theTranslatedText.c_str());
if(inCentered)
{
this->DrawHudStringCentered(inX, inY, ScreenWidth(), theCharBuffer, theR, theG, theB);
}
else
{
this->DrawHudString(inX, inY, ScreenWidth(), theCharBuffer, theR, theG, theB);
}
}
}
bool gWarpHUDSprites = false;
float gWarpXAmount = 0.0f;
float gWarpYAmount = 0.0f;
float gWarpXSpeed = 0.0f;
float gWarpYSpeed = 0.0f;
void SetWarpHUDSprites(bool inMode, float inWarpXAmount = 0.0f, float inWarpYAmount = 0.0f, float inWarpXSpeed = 0.0f, float inWarpYSpeed = 0.0f)
{
gWarpHUDSprites = inMode;
gWarpXAmount = inWarpXAmount;
gWarpYAmount = inWarpYAmount;
gWarpXSpeed = inWarpXSpeed;
gWarpYSpeed = inWarpYSpeed;
}
void DrawScaledHUDSprite(int inSpriteHandle, int inMode, int inRowsInSprite = 1, int inX = 0, int inY = 0, int inWidth = ScreenWidth(), int inHeight = ScreenHeight(), int inForceSpriteFrame = -1, float inStartU = 0.0f, float inStartV = 0.0f, float inEndU = 1.0f, float inEndV = 1.0f, float inRotateUVRadians = 0.0f, bool inUVWrapsOverFrames = false)
{
// Count number of frames
int theNumFrames = SPR_Frames(inSpriteHandle);
//int theSpriteWidth = SPR_Width(inSpriteHandle, 0);
//int theSpriteHeight = SPR_Height(inSpriteHandle, 0);
//float theAspectRatio = theSpriteWidth/theSpriteHeight;
// ASSERT that the the number of rows makes sense for the number of frames
ASSERT(theNumFrames > 0);
float theFloatNumCols = (float)theNumFrames/inRowsInSprite;
int theNumCols = (int)theFloatNumCols;
ASSERT(theNumCols == theFloatNumCols);
//int theNumRows = theNumFrames/theNumCols;
int theNumRows = inRowsInSprite;
// Allow scaling of one frame, without tiling
if(inForceSpriteFrame != -1)
{
theNumRows = theNumCols = 1;
}
// Make sure coords are bounded to allowable ranges
inStartU = min(max(inStartU, kD3DErrorValue), 1.0f - kD3DErrorValue);
inStartV = min(max(inStartV, kD3DErrorValue), 1.0f - kD3DErrorValue);
inEndU = min(max(inEndU, kD3DErrorValue), 1.0f - kD3DErrorValue);
inEndV = min(max(inEndV, kD3DErrorValue), 1.0f - kD3DErrorValue);
if(inRotateUVRadians != 0.0f)
{
// Rotate all the UV coords
vec3_t theAngles(0.0f, 0.0f, inRotateUVRadians);
float theMatrix[3][4];
AngleMatrix(theAngles, theMatrix);
float theRotatedValues[3];
float theStartValues[3] = {inStartU, inStartV, 0.0f};
VectorRotate(theStartValues, theMatrix, theRotatedValues);
inStartU = theRotatedValues[0];
inStartV = theRotatedValues[1];
float theEndValues[3] = {inEndU, inEndV, 0.0f};
VectorRotate(theEndValues, theMatrix, theRotatedValues);
inEndU = theRotatedValues[0];
inEndV = theRotatedValues[1];
}
// Calculate width and height of each quad
int theQuadScreenWidth = inWidth/theNumCols;
int theQuadScreenHeight = inHeight/theNumRows;
//Vector thePickRay;
//int theHalfWidth = ScreenWidth/2;
//int theHalfHeight = ScreenHeight/2;
//CreatePickingRay(theHalfWidth, theHalfHeight, thePickRay);
//char gDebugMessage[256];
//sprintf(gDebugMessage, "(%d, %d): %f, %f, %f", theHalfWidth, theHalfHeight, thePickRay.x, thePickRay.y, thePickRay.z);
//CenterPrint(gDebugMessage);
//float theRenderOrigin[3];
//pVector theUp;
//pVector theRight;
//pVector theNormal;
//IEngineStudio.GetViewInfo(theRenderOrigin, (float*)&theUp, (float*)&theRight, (float*)&theNormal);
//Demo_WriteVector(TYPE_VIEWANGLES, v_angles);
//Demo_WriteVector(TYPE_VIEWORIGIN, v_origin);
vec3_t theRenderOrigin;
VectorCopy(GetViewOrigin(), theRenderOrigin);
vec3_t theForward, theRight, theUp;
AngleVectors(v_angles, theForward, theRight, theUp);
Vector theRenderOriginVector;
theRenderOriginVector.x = theRenderOrigin[0];
theRenderOriginVector.y = theRenderOrigin[1];
theRenderOriginVector.z = theRenderOrigin[2];
// This is the smallest value that displays and it still clips with the view model a little
const int kDistanceToProject = 10;
// create picking ray for upper left of quad
Vector theUpperLeftRay;
//CreatePickingRay(inX, inY, theUpperLeftRay);
CreatePickingRay(0, 0, theUpperLeftRay);
// create picking ray for lower left of quad
Vector theLowerLeftRay;
//CreatePickingRay(inX, inY+inHeight, theLowerLeftRay);
CreatePickingRay(0, ScreenHeight(), theLowerLeftRay);
// create picking ray for upper right of quad
Vector theUpperRightRay;
//CreatePickingRay(inX+inWidth, inY, theUpperRightRay);
CreatePickingRay(ScreenWidth(), 0, theUpperRightRay);
// project default distance along picking ray
Vector theUpperLeftWorldPos;
VectorMA(theRenderOrigin, kDistanceToProject, theUpperLeftRay, theUpperLeftWorldPos);
Vector theUpperRightWorldPos;
VectorMA(theRenderOrigin, kDistanceToProject, theUpperRightRay, theUpperRightWorldPos);
Vector theLowerLeftWorldPos;
VectorMA(theRenderOrigin, kDistanceToProject, theLowerLeftRay, theLowerLeftWorldPos);
// Create formula for plane
float thePlaneD;
Vector thePlaneNormal;
CalculatePlaneInfo(theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePlaneD, thePlaneNormal);
// loop through screen height
int theCurrentFrame = 0;
// Allow drawing of just one frame
if(inForceSpriteFrame != -1)
{
theCurrentFrame = inForceSpriteFrame;
}
for(int i = 0; i < theNumRows; i++)
{
// loop through screen width
for(int j = 0; j < theNumCols; j++)
{
// draw quad
gEngfuncs.pTriAPI->RenderMode(inMode);
gEngfuncs.pTriAPI->CullFace(TRI_NONE);
//gEngfuncs.pTriAPI->Brightness(1);
if(gEngfuncs.pTriAPI->SpriteTexture((struct model_s*)gEngfuncs.GetSpritePointer(inSpriteHandle), theCurrentFrame))
{
gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP );
//gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, 1.0f);
bool theIsFirstRow = (i == 0);
bool theIsFirstCol = (j == 0);
bool theIsLastRow = (i == (theNumRows-1));
bool theIsLastCol = (j == (theNumCols-1));
float theStartU = inStartU;
float theStartV = inStartV;
float theEndU = inEndU;
float theEndV = inEndV;
if(inUVWrapsOverFrames)
{
if((theNumCols > 1) && !theIsFirstCol)
{
theStartU = 0.0f;
}
if((theNumRows > 1) && !theIsFirstRow)
{
theStartV = 0.0f;
}
if((theNumCols > 1) && !theIsLastCol)
{
theEndU = 1.0f;
}
if((theNumRows > 1) && !theIsLastRow)
{
theEndV = 1.0f;
}
}
// Optionally warp XY coords using current time
int theWarpXStartAmount = 0;
int theWarpYStartAmount = 0;
int theWarpXEndAmount = 0;
int theWarpYEndAmount = 0;
if(gWarpHUDSprites)
{
float theCurrentTime = gHUD.GetTimeOfLastUpdate();
float theNormXAmount = theCurrentTime*gWarpXSpeed - (int)(theCurrentTime*gWarpXSpeed); // Get fractional part of second
float theNormYAmount = theCurrentTime*gWarpYSpeed - (int)(theCurrentTime*gWarpYSpeed);
float theSinusoidalNormXAmount = cos(theNormXAmount*2.0f*M_PI);
float theSinusoidalNormYAmount = sin(theNormYAmount*2.0f*M_PI);
float theXAmount = theSinusoidalNormXAmount*gWarpXAmount;// - gWarpUAmount/2.0f;
float theYAmount = theSinusoidalNormYAmount*gWarpYAmount;// - gWarpVAmount/2.0f;
if(!theIsFirstCol)
{
theWarpXStartAmount = theXAmount*ScreenWidth();
}
if(!theIsLastCol)
{
theWarpXEndAmount = theXAmount*ScreenWidth();
}
if(!theIsFirstRow)
{
theWarpYStartAmount = theYAmount*ScreenHeight();
}
if(!theIsLastRow)
{
theWarpYEndAmount = theYAmount*ScreenHeight();
}
}
// Compensate for gamma
float theGammaSlope = gHUD.GetGammaSlope();
float theColorComponent = 1.0f/theGammaSlope;
gEngfuncs.pTriAPI->Color4f(theColorComponent, theColorComponent, theColorComponent, 1.0f);
Vector thePoint;
//float theMinXPercentage = (float)j/theNumCols;
//float theMaxXPercentage = (float)(j+1)/theNumCols;
//float theMinYPercentage = (float)i/theNumRows;
//float theMaxYPercentage = (float)(i+1)/theNumRows;
int theMinXPos = inX + ((float)j/theNumCols)*inWidth + theWarpXStartAmount;
int theMinYPos = inY + ((float)i/theNumRows)*inHeight + theWarpYStartAmount;
int theMaxXPos = inX + ((float)(j+1)/theNumCols)*inWidth + theWarpXEndAmount;
int theMaxYPos = inY + ((float)(i+1)/theNumRows)*inHeight + theWarpYEndAmount;
// Lower left
Vector thePointOne;
//BuildLerpedPoint(theMinXPercentage, theMaxYPercentage, theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePointOne);
CalculatePointOnPlane(theMinXPos, theMaxYPos, theRenderOriginVector, thePlaneNormal, thePlaneD, thePointOne);
float theU = theStartU;
float theV = theEndV;
gEngfuncs.pTriAPI->TexCoord2f(theU, theV);// 0,1
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePointOne);
// Upper left
Vector thePointTwo;
//BuildLerpedPoint(theMinXPercentage, theMinYPercentage, theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePointTwo);
CalculatePointOnPlane(theMinXPos, theMinYPos, theRenderOriginVector, thePlaneNormal, thePlaneD, thePointTwo);
theU = theStartU;
theV = theStartV;
//gEngfuncs.pTriAPI->TexCoord2f(inStartU, inStartV); // 0,0
gEngfuncs.pTriAPI->TexCoord2f(theU, theV);// 0,1
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePointTwo);
// Lower right
Vector thePointFour;
//BuildLerpedPoint(theMaxXPercentage, theMaxYPercentage, theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePointFour);
CalculatePointOnPlane(theMaxXPos, theMaxYPos, theRenderOriginVector, thePlaneNormal, thePlaneD, thePointFour);
theU = theEndU;
theV = theEndV;
//gEngfuncs.pTriAPI->TexCoord2f(inEndU, inEndV);// 1,1
gEngfuncs.pTriAPI->TexCoord2f(theU, theV);// 0,1
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePointFour);
// Upper right
Vector thePointThree;
//BuildLerpedPoint(theMaxXPercentage, theMinYPercentage, theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePointThree);
CalculatePointOnPlane(theMaxXPos, theMinYPos, theRenderOriginVector, thePlaneNormal, thePlaneD, thePointThree);
theU = theEndU;
theV = theStartV;
//gEngfuncs.pTriAPI->TexCoord2f(inEndU, inStartV); // 1,0
gEngfuncs.pTriAPI->TexCoord2f(theU, theV);// 0,1
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePointThree);
gEngfuncs.pTriAPI->End();
}
// Increment frame
theCurrentFrame++;
// Allow drawing of just one frame
if(inForceSpriteFrame != -1)
{
theCurrentFrame = inForceSpriteFrame;
}
// increment current x and y
//theCurrentScreenX += theQuadScreenWidth;
}
//theCurrentScreenX = 0;
//theCurrentScreenY += theQuadScreenHeight;
}
}
void DrawVariableScaledHUDSprite(float inFactor, int inSpriteHandle, int inMode, int inX, int inY, int inWidth, int inHeight)
{
// Draw as two scaled sprites, one for the level and one for the "empty" level
// Assumes that sprite has two frames, with the empty level being frame 0 and the full frame being frame 1
int theWidth = inWidth;
float theStartU = 0.0f;
float theEndU = 1.0f;
int theHeight = inFactor*inHeight;
float theStartV = 1.0f - inFactor;
float theEndV = 1.0f;
int theX = inX;
int theY = inY + inHeight - theHeight;
DrawScaledHUDSprite(inSpriteHandle, inMode, 1, theX, theY, theWidth, theHeight, 1, theStartU, theStartV, theEndU, theEndV);
// Draw background
theHeight = (1.0f - inFactor)*inHeight;
theY = inY;
theStartV = 0.0f;
theEndV = 1.0f - inFactor;
DrawScaledHUDSprite(inSpriteHandle, inMode, 1, theX, theY, theWidth, theHeight, 0, theStartU, theStartV, theEndU, theEndV);
}
void DrawSpriteOnGroundAtPoint(vec3_t inOrigin, int inRadius, HSPRITE inSprite, int inRenderMode = kRenderNormal, int inFrame = 0, float inAlpha = 1.0f)
{
if(gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(inSprite), inFrame))
{
gEngfuncs.pTriAPI->CullFace(TRI_NONE);
gEngfuncs.pTriAPI->RenderMode(inRenderMode);
//gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture );
//gEngfuncs.pTriAPI->Color4f(inR, inG, inB, inA);
gEngfuncs.pTriAPI->Begin(TRI_TRIANGLE_STRIP);
// Draw one quad
vec3_t thePoint = inOrigin;
float theGammaSlope = gHUD.GetGammaSlope();
ASSERT(theGammaSlope > 0.0f);
float theColorComponent = 1.0f/theGammaSlope;
gEngfuncs.pTriAPI->Color4f(theColorComponent, theColorComponent, theColorComponent, inAlpha);
gEngfuncs.pTriAPI->Brightness(1.6f);
thePoint[0] = inOrigin[0] - inRadius;
thePoint[1] = inOrigin[1] - inRadius;
gEngfuncs.pTriAPI->TexCoord2f(0, 0);
gEngfuncs.pTriAPI->Vertex3f(thePoint[0], thePoint[1], thePoint[2]);
thePoint[0] = inOrigin[0] - inRadius;
thePoint[1] = inOrigin[1] + inRadius;
gEngfuncs.pTriAPI->TexCoord2f(0, 1);
gEngfuncs.pTriAPI->Vertex3f(thePoint[0], thePoint[1], thePoint[2]);
thePoint[0] = inOrigin[0] + inRadius;
thePoint[1] = inOrigin[1] - inRadius;
gEngfuncs.pTriAPI->TexCoord2f(1, 0);
gEngfuncs.pTriAPI->Vertex3f(thePoint[0], thePoint[1], thePoint[2]);
thePoint[0] = inOrigin[0] + inRadius;
thePoint[1] = inOrigin[1] + inRadius;
gEngfuncs.pTriAPI->TexCoord2f(1, 1);
gEngfuncs.pTriAPI->Vertex3f(thePoint[0], thePoint[1], thePoint[2]);
gEngfuncs.pTriAPI->End();
gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}
}
void AvHHud::DrawPlayerNames()
{
bool inReadyRoom = false;//(this->GetPlayMode() == PLAYMODE_READYROOM);
bool inTopDownMode = this->GetInTopDownMode();
if(inTopDownMode || inReadyRoom /*&& !gEngfuncs.pDemoAPI->IsPlayingback()*/)
{
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
if(theLocalPlayer)
{
int theLocalPlayerIndex = theLocalPlayer->index;
// Loop through all players
for(int i = 1; i <= kMaxPlayers; i++)
{
if((i != theLocalPlayerIndex) && AvHCUGetIsEntityInPVSAndVisible(i))
{
cl_entity_s* theCurrentPlayer = gEngfuncs.GetEntityByIndex(i);
bool theDrawEntity = (inReadyRoom || (theCurrentPlayer && theCurrentPlayer->player && (AvHTeamNumber(theCurrentPlayer->curstate.team) == this->GetHUDTeam()) && (i != theLocalPlayerIndex)) );
if(theDrawEntity)
{
string theEntityName;
bool theIsEnemy;
if(this->GetEntityInfoString(i, theEntityName, theIsEnemy))
{
vec3_t theEntityOrigin;
VectorCopy(theCurrentPlayer->curstate.origin, theEntityOrigin);
theEntityOrigin.z += AvHCUGetIconHeightForPlayer((AvHUser3)theCurrentPlayer->curstate.iuser3);
// If they are on screen
Vector theScreenPos;
if(AvHCUWorldToScreen(theEntityOrigin, (float*)&theScreenPos))
{
// Set color
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
// If selected, draw in different color
if(inTopDownMode)
{
bool theIsSelected = (std::find(this->mSelected.begin(), this->mSelected.end(), i) != this->mSelected.end());
if(theIsSelected)
{
// Selected color
UnpackRGB(theR, theG, theB, RGB_MARINE_SELECTED);
if(GetHasUpgrade(theCurrentPlayer->curstate.iuser4, MASK_PARASITED))
{
string thePrePendString;
LocalizeString(kParasited, thePrePendString);
theEntityName = string(theEntityName + " (" + thePrePendString + ")");
// Set color to parasited color
UnpackRGB(theR, theG, theB, RGB_MARINE_PARASITED);
}
}
}
// Set text color draw in different color
this->mTopDownPlayerNameMessage.SetRGB(theR, theG, theB);
this->mTopDownPlayerNameMessage.SetIgnoreFadeForLifetime(true);
// Set the message info and draw it
this->mTopDownPlayerNameMessage.SetText(theEntityName);
// Set position
Vector theNormPos;
float theNormX = theScreenPos.x/ScreenWidth();
int theBoxHeight = this->mTopDownPlayerNameMessage.GetScreenHeight();
float theNormY = (theScreenPos.y - theBoxHeight)/ScreenHeight();
if((inTopDownMode && !this->GetIsRegionBlockedByUI(theNormX, theNormY)) || inReadyRoom)
{
this->mTopDownPlayerNameMessage.SetNormalizedScreenX(theNormX);
this->mTopDownPlayerNameMessage.SetNormalizedScreenY(theNormY);
this->mTopDownPlayerNameMessage.SetCentered(true);
this->mTopDownPlayerNameMessage.SetNormalizedMaxWidth(kReticleMaxWidth);
this->mTopDownPlayerNameMessage.Draw();
}
}
}
}
}
}
}
}
}
//bool AvHHud::ChopStringOfMaxScreenWidth(int inMaxScreenWidth, string& ioBaseString, string& outChoppedString)
//{
// // Loop backwards through the string, until we get a string that fits in this screen width
// int theCurrentLength = ioBaseString.length();
// int theMaxLength = ioBaseString.length();
// bool theSuccess = false;
//
// while(!theSuccess)
// {
// string theCurrentString = ioBaseString.substr(0, theCurrentLength);
// int theCurrentStringScreenWidth = this->GetHudStringWidth(theCurrentString.c_str());
// if(theCurrentStringScreenWidth <= inMaxScreenWidth)
// {
// // Look for a word to break the line
// while((theCurrentLength > 0) && !theSuccess)
// {
// char theCurrentChar = ioBaseString[theCurrentLength-1];
// if((theCurrentChar == ' ') || (theCurrentLength == theMaxLength))
// {
// outChoppedString = ioBaseString.substr(0, theCurrentLength);
// ioBaseString = ioBaseString.substr(theCurrentLength, ioBaseString.length() - theCurrentLength);
// theSuccess = true;
// break;
// }
// else
// {
// theCurrentLength--;
// }
// }
// }
// else
// {
// theCurrentLength--;
// }
// }
//
// return theSuccess;
//}
void AvHHud::DrawReticleInfo()
{
this->mReticleMessage.Draw();
// if(this->mReticleInfoText != "")
// {
// const float kMaxWidth = .3f;
// int kMaxScreenWidth = kMaxWidth*ScreenWidth;
//
// StringList theStringList;
// string theHelpString = this->mReticleInfoText;
//
// do
// {
// string theNewString;
// if(ChopStringOfMaxScreenWidth(kMaxScreenWidth, theHelpString, theNewString))
// {
// theStringList.push_back(theNewString);
// }
// else
// {
// theHelpString = "";
// }
// }
// while(theHelpString != "");
//
// // For each line, if the line contains any special markers, move them to their own lines
//
// // Compute max width of all the strings, add some extra for a frame
// int theBoxWidth = 0;
// StringList::iterator theStringListIter;
// for(theStringListIter = theStringList.begin(); theStringListIter != theStringList.end(); theStringListIter++)
// {
// int theCurrentScreenWidth = this->GetHudStringWidth(theStringListIter->c_str());
// theBoxWidth = max(theBoxWidth, theCurrentScreenWidth);
// }
// int theLineHSpacing = .01f*ScreenWidth;
// theBoxWidth += 2*theLineHSpacing;
//
// // Compute max height needed to contain all the strings, add some extra for a frame
// int theLineVSpacing = .01f*ScreenHeight();
// int theLineHeight = this->GetHudStringHeight();
// int theBoxHeight = 2*theLineVSpacing + (theStringList.size()*theLineHeight);
//
// int theFillStartX = this->mReticleInfoScreenX;
// int theFillStartY = this->mReticleInfoScreenY;
//
// theFillStartX -= theBoxWidth/2;
// theFillStartY -= theBoxHeight/2;
//
// // Draw nice border and shaded background
// const float kReticleInfoMaxAlpha = 25;
// float theNormalizedAlpha = this->mReticleInfoColorA/255;
// int theAlphaComponent = theNormalizedAlpha*kReticleInfoMaxAlpha;
//
// FillRGBA(theFillStartX, theFillStartY, theBoxWidth, theBoxHeight, this->mReticleInfoColorR, this->mReticleInfoColorG, this->mReticleInfoColorB, theAlphaComponent);
// vguiSimpleBox(theFillStartX, theFillStartY, theFillStartX + theBoxWidth, theFillStartY + theBoxHeight, this->mReticleInfoColorR, this->mReticleInfoColorG, this->mReticleInfoColorB, theAlphaComponent);
//
// // Now draw each line, non-centered, left-aligned
// int theLineNumber = 0;
// for(theStringListIter = theStringList.begin(); theStringListIter != theStringList.end(); theStringListIter++)
// {
// int theR = this->mReticleInfoColorR;
// int theG = this->mReticleInfoColorG;
// int theB = this->mReticleInfoColorB;
//
// // If the line starts with a marker, draw it in a special color
// //string theDamageMarker(kDamageMarker);
// //if(theStringListIter->substr(0, theDamageMarker.length()) == theDamageMarker)
// //{
// // // Draw string in yellow
// // theR = theG = 255;
// // theB = 25;
// //}
//
// int theBaseY = theFillStartY + theLineVSpacing + theLineNumber*theLineHeight;
//
// // Draw message (DrawHudStringCentered only centers in x)
// this->DrawHudString(theFillStartX + theLineHSpacing, theBaseY /*- theLineHeight/2*/, ScreenWidth, theStringListIter->c_str(), theR*theNormalizedAlpha, theG*theNormalizedAlpha, theB*theNormalizedAlpha);
//
// theLineNumber++;
// }
// }
}
void AvHHud::DrawToolTips()
{
if(!gEngfuncs.pDemoAPI->IsPlayingback())
{
this->mHelpMessage.Draw();
// Draw each one
for(AvHTooltipListType::iterator theIter = this->mTooltips.begin(); theIter != this->mTooltips.end(); theIter++)
{
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
theIter->SetRGB(theR, theG, theB);
theIter->Draw();
}
}
}
void AvHHud::DrawWorldSprite(int inSpriteHandle, int inRenderMode, vec3_t inWorldPosition, int inFrame, float inWorldSize)
{
vec3_t theUpperLeft;
vec3_t theLowerRight;
vec3_t theForward, theRight, theUp;
AngleVectors(v_angles, theForward, theRight, theUp);
vec3_t theToUpperLeft;
VectorAdd(-theRight, theUp, theToUpperLeft);
VectorNormalize(theToUpperLeft);
VectorMA(inWorldPosition, inWorldSize, theToUpperLeft, theUpperLeft);
vec3_t theToLowerRight;
VectorAdd(theRight, -theUp, theToLowerRight);
VectorNormalize(theToLowerRight);
VectorMA(inWorldPosition, inWorldSize, theToLowerRight, theLowerRight);
vec3_t theScreenUpperLeft;
vec3_t theScreenLowerRight;
// World to screen returns true if the world pos is behind the viewer
if(!gEngfuncs.pTriAPI->WorldToScreen((float*)theUpperLeft, (float*)theScreenUpperLeft))
{
if(!gEngfuncs.pTriAPI->WorldToScreen((float*)theLowerRight, (float*)theScreenLowerRight))
{
// If the sprite is behind you, push it to the bottom or top of the screen
// cl_entity_t* theLocalPlayer = gEngfuncs.GetLocalPlayer();
// ASSERT(theLocalPlayer);
//
// vec3_t theDirectionToOrder;
// VectorSubtract(inWorldPosition, theLocalPlayer->origin, theDirectionToOrder);
// float theDotProduct = DotProduct(theDirectionToOrder, theLocalPlayer->angles);
// if(theDotProduct < 0)
// {
// if(theWorldPos.z < theLocalPlayer->origin.z)
// {
// theY = theScreenHeight - theSpriteHeight - theScreenBorder;
// }
// else
// {
// theY = theScreenBorder;
// }
// vec3_t theCrossProduct;
// theCrossProduct = CrossProduct(theLocalPlayer->angles, theDirectionToOrder);
//
// // It's to our right
// if(theCrossProduct.z > 0)
// {
// theX = theScreenWidth - theSpriteWidth - theScreenBorder;
// }
// else
// {
// theX = theScreenBorder;
// }
// }
// float theDistanceToLocation = (float)VectorDistance(inWorldPosition, theLocalPlayer->origin);
// const theMaxDistance = 1500;
// float theEffectiveDistance = min(theDistanceToLocation, theMaxDistance);
// const int theMinColorComponent = 100;
// int theColorComponent = max(theMinColorComponent, 255 - ((theEffectiveDistance/theMaxDistance)*255));
//SPR_Set(inSpriteHandle, theColorComponent, theColorComponent, theColorComponent);
////SPR_DrawHoles((int)0, theX, theY, NULL);
//if(inRenderMode == kRenderNormal)
//{
// SPR_Draw(inFrame, theX, theY, NULL);
//}
//else if(inRenderMode == kRenderTransAdd)
//{
// SPR_DrawAdditive(inFrame, theX, theY, NULL);
//}
float theScreenX = XPROJECT(theScreenUpperLeft.x);
float theScreenY = YPROJECT(theScreenUpperLeft.y);
float theWidth = XPROJECT(theScreenLowerRight.x) - theScreenX;
float theHeight = YPROJECT(theScreenLowerRight.y) - theScreenY;
//DrawScaledHUDSprite(inSpriteHandle, inRenderMode, 1, theScreenX, theScreenY, theWidth, theHeight, inFrame);
AvHSpriteSetColor(1, 1, 1);
AvHSpriteSetRenderMode(inRenderMode);
AvHSpriteDraw(inSpriteHandle, inFrame, theScreenX, theScreenY, theScreenX + theWidth, theScreenY + theHeight, 0, 0, 1, 1);
}
}
}
void AvHHud::DrawOrderIcon(const AvHOrder& inOrder)
{
if(this->mOrderSprite)
{
int theNumFrames = SPR_Frames(this->mOrderSprite);
int theCurrentFrame = this->GetFrameForOrderType(inOrder.GetOrderType());
if((theCurrentFrame >= 0) && (theCurrentFrame < theNumFrames))
{
vec3_t theWorldPos;
inOrder.GetLocation(theWorldPos);
if ( inOrder.GetOrderType() == ORDERTYPET_ATTACK ) {
theWorldPos[2]+=kAttackOrderZOffset;
}
// Draw icon above pos, text below
theWorldPos.z += BALANCE_VAR(kOrderIconDrawSize);
this->DrawWorldSprite(this->mOrderSprite, kRenderTransAdd, theWorldPos, theCurrentFrame, BALANCE_VAR(kOrderIconDrawSize));
// If the order is our own order, draw the order indicator around it
if((this->GetHUDPlayMode() == PLAYMODE_PLAYING) && this->GetIsMarine() && !this->GetInTopDownMode())
{
this->DrawWorldSprite(this->mMarineOrderIndicator, kRenderTransAdd, theWorldPos, 0, BALANCE_VAR(kOrderIconDrawSize));
//DrawScaledHUDSprite(theSpriteHandle, kRenderNormal, 1, thePosX, thePosY, theWidth, theHeight, theFrame, theStartU, theStartV, theEndU, theEndV);
}
}
}
}
void AvHHud::DrawOrderText(const AvHOrder& inOrder)
{
int theIndex = (int)(inOrder.GetOrderType());
// Now draw text describing the waypoint
string theTitle;
sprintf(theTitle, "Order%d", theIndex);
string theLocalizedTitle(" ");
LocalizeString(theTitle.c_str(), theLocalizedTitle);
if((theIndex == ORDERTYPET_BUILD) || (theIndex == ORDERTYPET_GUARD) || (theIndex == ORDERTYPET_GET))
{
AvHUser3 theUser3 = inOrder.GetTargetUser3Type();
string theUser3Name;
if(this->GetTranslatedUser3Name(theUser3, theUser3Name))
{
// "Get %s" -> "Get heavy machine gun"
// "Guard %s -> "Guard soldier"
// "Build %s" -> "Build sentry turret"
string theTitleWithTarget;
sprintf(theTitleWithTarget, theLocalizedTitle.c_str(), theUser3Name.c_str());
theLocalizedTitle = theTitleWithTarget;
}
}
vec3_t theOrderLocation;
inOrder.GetLocation(theOrderLocation);
// Because the commander may not have information about the players heading to this waypoint (outside of his PVS), we
// can't draw a range for the commander
string theRangeDisplayString;
if(!this->GetInTopDownMode())
{
float theDistanceToWaypoint = VectorDistance(gPredictedPlayerOrigin, theOrderLocation);
int theVisibleDistance = max(1, (int)theDistanceToWaypoint/100);
string theVisibleUnits;
if(LocalizeString("Range", theVisibleUnits))
{
sprintf(theRangeDisplayString, theVisibleUnits.c_str(), theVisibleDistance);
}
}
string theLocationOfOrder;
theLocationOfOrder = this->GetNameOfLocation(theOrderLocation);
// It's OK if this fails, as only official maps will have these translated
string theTranslatedLocation = theLocationOfOrder;
LocalizeString(theLocationOfOrder.c_str(), theTranslatedLocation);
Vector theScreenPos;
if(AvHCUWorldToScreen((float*)theOrderLocation, (float*)&theScreenPos))
{
float theNormX = theScreenPos.x/ScreenWidth();
float theNormY = theScreenPos.y/ScreenHeight();
if(!this->GetIsRegionBlockedByUI(theNormX, theNormY))
{
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
string theFirstLine = theLocalizedTitle;
if(theRangeDisplayString != "")
{
theFirstLine += string(" : ") + theRangeDisplayString;
}
// Draw order (icon above world position, text below it)
int theBaseX = theScreenPos.x;
int theBaseY = theScreenPos.y;
int theStringHeight = this->GetHudStringHeight();
this->DrawHudStringCentered(theBaseX, theBaseY + theStringHeight, ScreenWidth(), theFirstLine.c_str(), theR, theG, theB);
// Draw location below it
this->DrawHudStringCentered(theBaseX, theBaseY + 2*theStringHeight, ScreenWidth(), theTranslatedLocation.c_str(), theR, theG, theB);
}
}
}
void AvHHud::DrawOrders()
{
if(1/*!this->mIsRenderingSelectionView*/)
{
// Draw them blinking for soldiers, but always for commanders
float theFractionalLastUpdate = this->mTimeOfLastUpdate - (int)this->mTimeOfLastUpdate;
if((theFractionalLastUpdate > .25f) || (this->GetHUDUser3() == AVH_USER3_COMMANDER_PLAYER))
{
OrderListType theOrders = this->GetOrderList();
EntityListType theDrawPlayerList = this->GetDrawPlayerOrders();
// Run through the order list type
for(OrderListType::iterator theIter = theOrders.begin(); theIter != theOrders.end(); theIter++)
{
// For each one, if the order is for a player in the theDrawPlayerList, draw it
vec3_t theOrderLocation;
theIter->GetLocation(theOrderLocation);
if(theIter->GetOrderTargetType() == ORDERTARGETTYPE_TARGET)
{
int theTargetIndex = theIter->GetTargetIndex();
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(theTargetIndex);
if(theEntity)
{
//voogru: dont follow if they are cloaked, leave the waypoint active so they have a clue where they may be at, the wp should snap back to the baddy
//once they are spotted again.
if(theEntity->curstate.rendermode != kRenderTransTexture && theEntity->curstate.renderamt > 128)
VectorCopy(theEntity->origin, theOrderLocation);
}
}
// Draw the order if the order is for any plays that are in our draw player list
bool theDrawWaypoint = false;
EntityInfo theReceiverPlayer = theIter->GetReceiver();
EntityListType::iterator theSearchIter = std::find(theDrawPlayerList.begin(), theDrawPlayerList.end(), theReceiverPlayer);
if(theSearchIter != theDrawPlayerList.end() && *theSearchIter == theReceiverPlayer)
{
//gEngfuncs.pEfxAPI->R_ParticleLine((float*)theEntity->origin, (float*)theOrderLocation, 0, 255, 0, .05f);
theDrawWaypoint = true;
}
if(theDrawWaypoint)
{
this->DrawOrderIcon(*theIter);
this->DrawOrderText(*theIter);
}
}
}
}
}
int AvHHud::GetHelpIconFrameFromUser3(AvHUser3 inUser3)
{
int theFrame = -1;
switch(inUser3)
{
case AVH_USER3_WELD:
theFrame = 0;
break;
case AVH_USER3_MARINEITEM:
theFrame = 1;
break;
case AVH_USER3_HIVE:
theFrame = 2;
break;
//case AVH_USER3_USEABLE:
// theFrame = 3;
// break;
case AVH_USER3_COMMANDER_STATION:
theFrame = 4;
break;
//case AVH_USER3_BREAKABLE:
// theFrame = 5;
// break;
}
return theFrame;
}
HSPRITE AvHHud::GetHelpSprite() const
{
return this->mHelpSprite;
}
void AvHHud::DrawHelpIcons()
{
// Lookup table
// Only draw if enabled
//if(gEngfuncs.pfnGetCvarFloat(kvAutoHelp))
//{
// Iterate through help icons, drawing each one if we have an sprite for it
for(HelpIconListType::iterator theIter = this->mHelpIcons.begin(); theIter != this->mHelpIcons.end(); theIter++)
{
int theUser3 = theIter->second;
int theFrame = GetHelpIconFrameFromUser3(AvHUser3(theUser3));
// Lookup sprite to see if it's loaded
// if(this->mHelpSprites[theUser3] == 0)
// {
// string theIconName = string(kHelpIconPrefix) + MakeStringFromInt(theUser3) + ".spr";
// this->mHelpSprites[theUser3] = Safe_SPR_Load(theIconName.c_str());
// }
//
// int theSpriteHandle = this->mHelpSprites[theUser3];
// if(theSpriteHandle > 0)
// {
// // Draw icon at entity center
// this->DrawWorldSprite(theSpriteHandle, kRenderTransAdd, theIter->first, 0);
// }
if((theFrame >= 0) && this->mHelpSprite)
{
this->DrawWorldSprite(this->mHelpSprite, kRenderTransAdd, theIter->first, theFrame, kHelpIconDrawSize);
}
}
//}
}
// inDrawMode determines if we're drawing text or sprites
void AvHHud::DrawHUDStructureNotification()
{
const float kHUDStructureNotificationStartX = .02f;
const float kHUDStructureNotificationStartY = .11f;
const float kHUDStructureNotificationIconWidth = .03f;
const float kHUDStructureNotificationIconHeight = kHUDStructureNotificationIconWidth*1.333f;
const float kHUDStructureNotificationIconHorizontalSpacing = .01f;
const float kHUDStructureNotificationIconVerticalSpacing = kHUDStructureNotificationIconHorizontalSpacing*1.333f;
const float kHUDStructureNotificationMaxTextWidth = .2f;
// Draw them all in order
if(this->GetIsAlive() && CVAR_GET_FLOAT(kvBuildMessages))
{
// Get starting coords
float theCurrentX = kHUDStructureNotificationStartX;
float theCurrentY = kHUDStructureNotificationStartY;
for(StructureHUDNotificationListType::iterator theIter = this->mStructureNotificationList.begin(); theIter != this->mStructureNotificationList.end(); theIter++)
{
// Draw icon
AvHMessageID theIconTech = theIter->mStructureID;
int theFrame = 0;
this->DrawTechTreeSprite(theIconTech, theCurrentX*ScreenWidth(), theCurrentY*ScreenHeight(), kHUDStructureNotificationIconWidth*ScreenWidth(), kHUDStructureNotificationIconHeight*ScreenHeight(), theFrame);
string theLocationName = this->GetNameOfLocation(theIter->mLocation);
if(theLocationName != "")
{
int theStartX = (theCurrentX + kHUDStructureNotificationIconWidth + kHUDStructureNotificationIconHorizontalSpacing)*ScreenWidth();
this->DrawTranslatedString(theStartX, theCurrentY*ScreenHeight(), theLocationName.c_str(), false, true);
}
// Increment coords
theCurrentY += (kHUDStructureNotificationIconHeight + kHUDStructureNotificationIconVerticalSpacing);
}
}
}
void AvHHud::DrawInfoLocationText()
{
string theTimeLeftText;
// Get drawing color and position
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
// Get position of health and draw to the right of it (must be left-justified)
int theX = 0;
int theY = 0;
if(this->GetInTopDownMode())
{
const float kLeftInset = .4f;
theX = mViewport[0] + kLeftInset*ScreenWidth();
theY = mViewport[1] + mViewport[3] - (1-.78f)*ScreenHeight();
}
// Draw info location text the same for aliens and marines
else if(this->GetHUDUser3() != AVH_USER3_ALIEN_EMBRYO)
{
const float kLeftInset = .08f;
theX = mViewport[0] + kLeftInset*ScreenWidth();
theY = mViewport[1] + mViewport[3] - (1-.88f)*ScreenHeight();
}
int theLeftEdge = theX;
// Draw location text, translation if possible
string theLocalizedLocationText;
if(this->mLocationText != "")
{
LocalizeString(this->mLocationText.c_str(), theLocalizedLocationText);
if(theLocalizedLocationText[0] == '#')
{
theLocalizedLocationText = theLocalizedLocationText.substr(1, theLocalizedLocationText.size());
}
// Draw handicap text as well
int theHandicap = (int)this->GetHUDHandicap();
if(theHandicap < 100)
{
// draw "(handicap 70%)"
string theHandicapString;
if(LocalizeString(kHandicap, theHandicapString))
{
char theFormattedHandicapString[256];
sprintf(theFormattedHandicapString, " (%d%% %s)", theHandicap, theHandicapString.c_str());
theLocalizedLocationText += string(theFormattedHandicapString);
}
}
// Draw info location
if(theLocalizedLocationText != "")
{
char theCharArray[512];
sprintf(theCharArray, "%s", theLocalizedLocationText.c_str());
this->DrawHudString(theX, theY, ScreenWidth(), theCharArray, theR, theG, theB);
}
}
// Don't draw time when playing back, it isn't right and not worth breaking backward-compatibility over.
// TODO: Draw time next time demo version changes
if(!gEngfuncs.pDemoAPI->IsPlayingback() && this->GetHUDUser3() != AVH_USER3_ALIEN_EMBRYO)
{
// Whether we draw first line or not, increment for second line below
theY += this->GetHudStringHeight();
// Optionally draw time left below it
int theTimeLimitSeconds = (int)this->GetGameTimeLimit();
int theTimeElapsed = this->GetGameTime();
int theMinutesElapsed = theTimeElapsed/60;
int theSecondsElapsed = theTimeElapsed%60;
int theTimeLeftSeconds = theTimeLimitSeconds - theTimeElapsed;
int theMinutesLeft = theTimeLeftSeconds/60;
int theSecondsLeft = theTimeLeftSeconds%60;
int theMinutesLimit = theTimeLimitSeconds/60;
int theSecondsLimit = theTimeLimitSeconds%60;
// If we're in tournament mode or playing Combat, draw the timelimit
bool theTournyMode = (gHUD.GetServerVariableFloat(kvTournamentMode) > 0);
bool theDisplayTimeLimit = theTournyMode || gHUD.GetIsCombatMode();
string theGameTimeText;
if(LocalizeString(kGameTime, theGameTimeText))
{
bool theTimeVisible = true;
// Flash time when we're almost out of time
if((theMinutesLeft < 1) && this->GetGameStarted() && theDisplayTimeLimit)
{
float theTime = gHUD.GetTimeOfLastUpdate();
float theTimeFraction = theTime - floor(theTime);
if(theTimeFraction < .5f)
{
theTimeVisible = false;
}
}
// Game time - 12:43
char theGameTimeCStr[256];
sprintf(theGameTimeCStr, " - %02d:%02d", theMinutesElapsed, theSecondsElapsed);
theGameTimeText += string(theGameTimeCStr);
if(theTimeVisible)
{
this->DrawHudString(theX, theY, ScreenWidth(), theGameTimeText.c_str(), theR, theG, theB);
}
// Increment X so time limit is drawn properly
theX += this->GetHudStringWidth(theGameTimeText.c_str());
}
if(theDisplayTimeLimit)
{
string theTimeLimitString;
if(LocalizeString(kTimeLimit, theTimeLimitString))
{
// Format: Time limit - 60:00
char theTimeLimitCStr[256];
sprintf(theTimeLimitCStr, " %s - %02d:%02d", theTimeLimitString.c_str(), theMinutesLimit, theSecondsLimit);
string theTimeLimitText = string(theTimeLimitCStr);
this->DrawHudString(theX, theY, ScreenWidth(), theTimeLimitText.c_str(), theR, theG, theB);
}
if(gHUD.GetIsCombatMode())
{
theY += this->GetHudStringHeight();
// Draw "attacking" or "defending"
AvHTeamNumber theTeamNumber = this->GetHUDTeam();
string theDisplayString = "";
if(theTeamNumber != TEAM_IND)
{
if(theTeamNumber == this->GetCombatAttackingTeamNumber())
{
LocalizeString(kAttacking, theDisplayString);
}
else
{
LocalizeString(kDefending, theDisplayString);
}
this->DrawHudString(theLeftEdge, theY, ScreenWidth(), theDisplayString.c_str(), theR, theG, theB);
}
}
}
}
}
void AvHHud::DrawMouseCursor(int inBaseX, int inBaseY)
{
if ( g_iVisibleMouse && !(this->GetInTopDownMode() && gEngfuncs.pDemoAPI->IsPlayingback()) )
{
HSPRITE theCursorSprite;
int theCursorFrame;
GetCursor(theCursorSprite, theCursorFrame);
if (theCursorSprite > 0)
{
float theGammaSlope = this->GetGammaSlope();
ASSERT(theGammaSlope > 0.0f);
/*
int theColorComponent = 255/theGammaSlope;
SPR_Set(this->mCursorSprite, theColorComponent, theColorComponent, theColorComponent);
// Draw the logo at 20 fps
//SPR_DrawAdditive( 0, this->mMouseCursorX - inBaseX, this->mMouseCursorY - inBaseY, NULL );
const int kMouseHotSpotX = -1;
const int kMouseHotSpotY = -1;
SPR_DrawHoles(this->mCurrentCursorFrame, this->mMouseCursorX - inBaseX - kMouseHotSpotX, this->mMouseCursorY - inBaseY - kMouseHotSpotY, NULL );
*/
// Draw the mouse cursor.
const int kMouseHotSpotX = -1;
const int kMouseHotSpotY = -1;
AvHSpriteBeginFrame();
AvHSpriteEnableVGUI(true);
AvHSpriteSetVGUIOffset(inBaseX, inBaseY);
float x = this->mMouseCursorX - kMouseHotSpotX;
float y = this->mMouseCursorY - kMouseHotSpotY;
float w = SPR_Width(theCursorSprite, theCursorFrame);
float h = SPR_Height(theCursorSprite, theCursorFrame);
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(theCursorSprite, theCursorFrame, x, y, x + w, y + h, 0, 0, 1, 1);
// Draw the marquee if it's visible.
if (mSelectionBoxVisible)
{
int sprite = Safe_SPR_Load(kWhiteSprite);
int r, g, b;
GetPrimaryHudColor(r, g, b, true, false);
AvHSpriteSetRenderMode(kRenderTransAdd);
AvHSpriteSetColor(r / 255.0, g / 255.0, b / 255.0, 0.3);
AvHSpriteSetDrawMode(kSpriteDrawModeFilled);
AvHSpriteDraw(sprite, 0, mSelectionBoxX1 + 1, mSelectionBoxY1 + 1, mSelectionBoxX2 - 1, mSelectionBoxY2 - 1, 0, 0, 1, 1);
AvHSpriteSetRenderMode(kRenderNormal);
AvHSpriteSetColor(1, 1, 1, 1);
AvHSpriteSetDrawMode(kSpriteDrawModeBorder);
AvHSpriteDraw(sprite, 0, mSelectionBoxX1, mSelectionBoxY1, mSelectionBoxX2, mSelectionBoxY2, 0, 0, 1, 1);
}
AvHSpriteEndFrame();
}
}
}
void AvHHud::DrawTopDownBG()
{
// If we're in top down mode, draw a black background
float theDrawBackgroundHeight = -1;//cl_drawbg->value;
// Draw the bottom plane at the map's min view height, unless overridden by cl_drawbg (this variable is for for testing purposes only)
if(theDrawBackgroundHeight == -1)
{
if(this->mMapExtents.GetDrawMapBG())
{
theDrawBackgroundHeight = this->mMapExtents.GetMinViewHeight();
}
}
if(theDrawBackgroundHeight != -1)
{
if(this->mBackgroundSprite)
{
// Build three points on plane described by max world dimensions at the draw background height
Vector theUpperLeftWorldPos(-kMaxMapDimension, kMaxMapDimension, theDrawBackgroundHeight);
Vector theUpperRightWorldPos(kMaxMapDimension, kMaxMapDimension, theDrawBackgroundHeight);
Vector theLowerLeftWorldPos(-kMaxMapDimension, -kMaxMapDimension, theDrawBackgroundHeight);
// Calculate plane info
float thePlaneD;
Vector thePlaneNormal;
CalculatePlaneInfo(theUpperLeftWorldPos, theUpperRightWorldPos, theLowerLeftWorldPos, thePlaneD, thePlaneNormal);
gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
gEngfuncs.pTriAPI->CullFace( TRI_NONE );
gEngfuncs.pTriAPI->Brightness( 1 );
if(gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(this->mBackgroundSprite), 0))
{
gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP );
gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, 1.0f);
Vector thePoint;
CalculatePointOnPlane(0, ScreenHeight(), GetViewOrigin(), thePlaneNormal, thePlaneD, thePoint);
gEngfuncs.pTriAPI->TexCoord2f(0, 1);
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePoint);
CalculatePointOnPlane(0, 0, GetViewOrigin(), thePlaneNormal, thePlaneD, thePoint);
gEngfuncs.pTriAPI->TexCoord2f(0, 0);
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePoint);
CalculatePointOnPlane(ScreenWidth(), ScreenHeight(), GetViewOrigin(), thePlaneNormal, thePlaneD, thePoint);
gEngfuncs.pTriAPI->TexCoord2f(1, 1);
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePoint);
CalculatePointOnPlane(ScreenWidth(), 0, GetViewOrigin(), thePlaneNormal, thePlaneD, thePoint);
gEngfuncs.pTriAPI->TexCoord2f(1, 0);
gEngfuncs.pTriAPI->Vertex3fv((float*)&thePoint);
// Add in some buffer because of perspective
// pVector ver;
// ver.z = theDrawBackgroundHeight;
//
// // Lower left
// gEngfuncs.pTriAPI->TexCoord2f(0,1);
// ver.x = -kMaxMapDimension;
// ver.y = -kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Upper left
// gEngfuncs.pTriAPI->TexCoord2f(0,0);
// ver.x = -kMaxMapDimension;
// ver.y = kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Upper right
// gEngfuncs.pTriAPI->TexCoord2f(1,0);
// ver.x = kMaxMapDimension;
// ver.y = kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Lower right
// gEngfuncs.pTriAPI->TexCoord2f(1,1);
// ver.x = kMaxMapDimension;
// ver.y = -kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
gEngfuncs.pTriAPI->End();
}
}
}
}
void AvHHud::PostModelRender(char* inModelName)
{
// Get our view model name
cl_entity_t* theViewEntity = gEngfuncs.GetViewModel();
if(theViewEntity)
{
// If this is our view model, that means we can now render our own stuff in screen space without z-buffering on top of everything else
if(theViewEntity->model)
{
if(!strcmp(theViewEntity->model->name, inModelName))
{
this->RenderNoZBuffering();
}
}
}
}
float AvHHud::GetHUDExperience() const
{
vec3_t theVUser4;
theVUser4.z = 0.0f;
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
if(theLocalPlayer)
{
theVUser4 = theLocalPlayer->curstate.vuser4;
}
if(g_iUser1 == OBS_IN_EYE)
{
cl_entity_t* theEnt = gEngfuncs.GetEntityByIndex(g_iUser2);
if(theEnt)
{
theVUser4 = theEnt->curstate.vuser4;
}
}
float theExperience = theVUser4.z/kNumericNetworkConstant;
return theExperience;
}
int AvHHud::GetHUDExperienceLevel() const
{
float theExperience = this->GetHUDExperience();
int theLevel = AvHPlayerUpgrade::GetPlayerLevel(theExperience);
return theLevel;
}
float AvHHud::GetHUDHandicap() const
{
float theHandicap = 100.0f;
AvHTeamNumber theTeamNumber = this->GetHUDTeam();
switch(theTeamNumber)
{
case TEAM_ONE:
theHandicap = this->GetServerVariableFloat(kvTeam1DamagePercent);
break;
case TEAM_TWO:
theHandicap = this->GetServerVariableFloat(kvTeam2DamagePercent);
break;
case TEAM_THREE:
theHandicap = this->GetServerVariableFloat(kvTeam3DamagePercent);
break;
case TEAM_FOUR:
theHandicap = this->GetServerVariableFloat(kvTeam4DamagePercent);
break;
}
return theHandicap;
}
AvHUser3 AvHHud::GetHUDUser3() const
{
AvHUser3 theUser3 = AVH_USER3_NONE;
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
if(theLocalPlayer)
{
theUser3 = (AvHUser3)(theLocalPlayer->curstate.iuser3);
}
if(g_iUser1 == OBS_IN_EYE)
{
cl_entity_t* theEnt = gEngfuncs.GetEntityByIndex(g_iUser2);
if(theEnt)
{
theUser3 = (AvHUser3)(theEnt->curstate.iuser3);
}
}
return theUser3;
}
AvHTeamNumber AvHHud::GetHUDTeam() const
{
AvHTeamNumber theTeamNumber = TEAM_IND;
cl_entity_s* thePlayer = this->GetVisiblePlayer();
if(thePlayer)
{
theTeamNumber = AvHTeamNumber(thePlayer->curstate.team);
}
return theTeamNumber;
}
int AvHHud::GetHUDUpgrades() const
{
int theUpgrades = 0;
cl_entity_s* thePlayer = this->GetVisiblePlayer();
if(thePlayer)
{
theUpgrades = thePlayer->curstate.iuser4;
}
return theUpgrades;
}
int AvHHud::GetHUDMaxArmor() const
{
int theHUDUpgrades = this->GetHUDUpgrades();
AvHUser3 theUser3 = this->GetHUDUser3();
int theMaxArmor = AvHPlayerUpgrade::GetMaxArmorLevel(theHUDUpgrades, theUser3);
return theMaxArmor;
}
int AvHHud::GetHUDMaxHealth() const
{
int theHUDUpgrades = this->GetHUDUpgrades();
AvHUser3 theUser3 = this->GetHUDUser3();
int theHUDExperienceLevel = this->GetHUDExperienceLevel();
int theMaxHealth = AvHPlayerUpgrade::GetMaxHealth(theHUDUpgrades, theUser3, theHUDExperienceLevel);
return theMaxHealth;
}
void AvHHud::GetPrimaryHudColor(int& outR, int& outG, int& outB, bool inIgnoreUpgrades, bool gammaCorrect) const
{
if(this->GetIsMarine())
{
UnpackRGB(outR, outG, outB, RGB_MARINE_BLUE);
}
else
{
// HUD turns green when we're frenzying
//if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_PRIMALSCREAM) && !inIgnoreUpgrades)
//{
// UnpackRGB(outR, outG, outB, RGB_GREENISH);
//}
//else
//{
UnpackRGB(outR, outG, outB, RGB_YELLOWISH);
//}
}
if (gammaCorrect)
{
// Take into account current gamma?
float theGammaSlope = this->GetGammaSlope();
outR /= theGammaSlope;
outG /= theGammaSlope;
outB /= theGammaSlope;
}
}
void AvHHud::HandleFog()
{
float theFogColor[3];
theFogColor[0] = this->mFogColor.x;
theFogColor[1] = this->mFogColor.y;
theFogColor[2] = this->mFogColor.z;
gEngfuncs.pTriAPI->Fog(theFogColor, this->mFogStart, this->mFogEnd, this->mFogActive);
}
void AvHHud::PreRenderFrame()
{
bool theRenderForTopDown = this->mInTopDownMode /*&& !this->mIsRenderingSelectionView*/;
if(!theRenderForTopDown)
{
this->HandleFog();
}
else
{
this->DrawTopDownBG();
// Now draw commander HUD scaled
//void CreatePickingRay( int mousex, int mousey, Vector& outVecPickingRay )
// static int theCommanderHUDSprite = 0;
// if(!theCommanderHUDSprite)
// {
// theCommanderHUDSprite = Safe_SPR_Load("sprites/.spr");
// }
//
// if(theCommanderHUDSprite)
// {
// gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
// gEngfuncs.pTriAPI->CullFace( TRI_NONE );
// gEngfuncs.pTriAPI->Brightness( 1 );
//
// if(gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(theCommanderHUDSprite), 0))
// {
// gEngfuncs.pTriAPI->Begin( TRI_QUADS );
//
// gEngfuncs.pTriAPI->Color4f(1.0f, 1.0f, 1.0f, .5f);
//
// pVector ver;
//
// // Lower left
// const float kMaxMapDimension = 4096;
// //ver.z = -kMaxMapDimension;
// ver.z = theDrawBackgroundHeight;
//
// gEngfuncs.pTriAPI->TexCoord2f(0,1);
// ver.x = -kMaxMapDimension;
// ver.y = -kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Upper left
// gEngfuncs.pTriAPI->TexCoord2f(0,0);
// ver.x = -kMaxMapDimension;
// ver.y = kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Upper right
// gEngfuncs.pTriAPI->TexCoord2f(1,0);
// ver.x = kMaxMapDimension;
// ver.y = kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// // Lower right
// gEngfuncs.pTriAPI->TexCoord2f(1,1);
// ver.x = kMaxMapDimension;
// ver.y = -kMaxMapDimension;
// gEngfuncs.pTriAPI->Vertex3fv((float*)&ver);
//
// gEngfuncs.pTriAPI->End();
// }
// }
}
AvHScriptManager::Instance()->DrawNormal();
}
void AvHHud::PostRenderFrame()
{
// Restore player angles and view position
// v_origin = gPlayerOrigin;
// v_angles = gPlayerAngles;
}
void AvHHud::DrawActionButtons()
{
// Look up AvHActionButtons component
AvHActionButtons* theActionButtons = NULL;
if(this->GetManager().GetVGUIComponentNamed(kActionButtonsComponents, theActionButtons))
{
int theNumCols = theActionButtons->GetNumCols();
int theNumRows = theActionButtons->GetNumRows();
// Iterate through num cols
for(int theCol = 0; theCol < theNumCols; theCol++)
{
// Iterate through num rows
for(int theRow = 0; theRow < theNumRows; theRow++)
{
// Get current ActionButton
ActionButton* theActionButton = theActionButtons->GetActionButtonAtPos(theCol, theRow);
ASSERT(theActionButton);
// Get message ID for button
AvHMessageID theMessageID = theActionButton->GetMessageID();
// Find the group that it belongs to (20, 30, 40, etc.)
int theMessageNumber = (int)theMessageID - (theMessageID % 10);
// // Load sprite if not loaded
// bool theSpriteLoaded = (this->mActionButtonSprites[theMessageNumber] > 0);
// if(!theSpriteLoaded)
// {
// // Build sprite name for message ID
// char theMessageNumberString[16];
// sprintf(theMessageNumberString, "%d", (int)theMessageNumber);
// //string theSpriteName = kTechTreeSpriteDirectory + string("/") + kTechTreeSpritePrefix + string(theMessageIDString) + string(".spr");
// string theSpriteName = kTechTreeSpriteDirectory + string("/") + kTechTreeSpritePrefix + string(theMessageNumberString) + string("s.spr");
// int theSpriteHandle = Safe_SPR_Load(theSpriteName.c_str());
//
// // Sprite handle can be 0, as I don't have sprites for all tech yet
// this->mActionButtonSprites[theMessageNumber] = theSpriteHandle;
// }
// Get pos and size for component
int thePosX, thePosY;
theActionButton->getPos(thePosX, thePosY);
int theWidth, theHeight;
theActionButton->getSize(theWidth, theHeight);
// Set sprite frame depending if button is available, active
bool theTechEnabled = theActionButton->GetTechEnabled();
bool theMouseOver = theActionButton->GetMouseOver();
bool theCostMet = theActionButton->GetCostMet();
// 0 = default
// 1 = highlighted
// 2 = dark
// 3 = red
int theFrame = 2;
// If it's enabled, or if it's an icon in the "menu navigation" category, allow it to be highlighted
if(theTechEnabled || (theMessageNumber == 80))
{
if(theCostMet)
{
if(theMouseOver)
{
theFrame = 1;
}
else
{
theFrame = 0;
}
}
else
{
theFrame = 3;
}
}
// Also highlight menu category headings for open menus, and for active nodes just pressed
if(gCommanderHandler.GetDisplayMenuMessageID() == theMessageID)
{
theFrame = 1;
}
else
{
AvHMessageID theMessageJustActivated = MESSAGE_NULL;
if(gCommanderHandler.GetAndClearTechNodePressed(theMessageJustActivated, false))
{
if(theMessageJustActivated == theMessageID)
{
if(theTechEnabled)
{
theFrame = 1;
}
}
}
}
this->DrawTechTreeSprite(theMessageID, thePosX, thePosY, theWidth, theHeight, theFrame);
}
}
}
}
int AvHHud::GetTechTreeSprite(AvHMessageID inMessageID)
{
// Find the group that it belongs to (20, 30, 40, etc.)
int theMessageNumber = (int)inMessageID - (inMessageID % 10);
// Load sprite if not loaded
bool theSpriteLoaded = (this->mActionButtonSprites[theMessageNumber] > 0);
if(!theSpriteLoaded && (theMessageNumber != 0))
{
// Build sprite name for message ID
char theMessageNumberString[16];
sprintf(theMessageNumberString, "%d", (int)theMessageNumber);
//string theSpriteName = kTechTreeSpriteDirectory + string("/") + kTechTreeSpritePrefix + string(theMessageIDString) + string(".spr");
string theSpriteName = kTechTreeSpriteDirectory + string("/") + kTechTreeSpritePrefix + string(theMessageNumberString) + string("s.spr");
int theSpriteHandle = Safe_SPR_Load(theSpriteName.c_str());
// Sprite handle can be 0, as I don't have sprites for all tech yet
this->mActionButtonSprites[theMessageNumber] = theSpriteHandle;
}
// Fetch sprite handle
int theSpriteHandle = this->mActionButtonSprites[theMessageNumber];
return theSpriteHandle;
}
void AvHHud::DrawTechTreeSprite(AvHMessageID inMessageID, int inPosX, int inPosY, int inWidth, int inHeight, int inFrame)
{
if(inMessageID != MESSAGE_NULL)
{
// Check for alien sprites
bool theIsAlienSprite = false;
int theSpriteHandle = 0;
int theRenderMode = kRenderTransAlpha; // kRenderNormal
switch(inMessageID)
{
case ALIEN_BUILD_DEFENSE_CHAMBER:
theIsAlienSprite = true;
inFrame = 0;
break;
case ALIEN_BUILD_OFFENSE_CHAMBER:
theIsAlienSprite = true;
inFrame = 1;
break;
case ALIEN_BUILD_MOVEMENT_CHAMBER:
theIsAlienSprite = true;
inFrame = 2;
break;
case ALIEN_BUILD_SENSORY_CHAMBER:
theIsAlienSprite = true;
inFrame = 3;
break;
case ALIEN_BUILD_RESOURCES:
theIsAlienSprite = true;
inFrame = 4;
break;
case ALIEN_BUILD_HIVE:
theIsAlienSprite = true;
inFrame = 5;
break;
}
float theStartU = 0.0f;
float theStartV = 0.0f;
float theEndU = 1.0f;
float theEndV = 1.0f;
if(theIsAlienSprite)
{
theRenderMode = kRenderTransAlpha;
theSpriteHandle = this->mAlienUIUpgradeCategories;
}
else
{
// Fetch sprite handle
theSpriteHandle = this->GetTechTreeSprite(inMessageID);
int theIndex = inMessageID % 10;
int theXIndex = theIndex % 4;
int theYIndex = (theIndex / 4);
theStartU = theXIndex*.25f;
theStartV = theYIndex*.25f;
theEndU = (theXIndex+1)*.25f;
theEndV = (theYIndex+1)*.25f;
}
if(theSpriteHandle > 0)
{
// Draw sprite scaled here
AvHSpriteSetRenderMode(theRenderMode);
AvHSpriteDraw(theSpriteHandle, inFrame, inPosX, inPosY, inPosX + inWidth, inPosY + inHeight, theStartU, theStartV, theEndU, theEndV);
}
}
}
void AvHHud::DrawHotgroups()
{
AvHMessageID theHotgroups[kNumHotkeyGroups] = {GROUP_SELECT_1, GROUP_SELECT_2, GROUP_SELECT_3, GROUP_SELECT_4, GROUP_SELECT_5};
// Run through list of hotgroups, drawing them if they exist
for(int i = 0; i < kNumHotkeyGroups; i++)
{
EntityListType& theHotgroup = this->mGroups[i];
if(theHotgroup.size() > 0)
{
// Get message ID to draw
AvHUser3 theGroupTypeUser3 = this->mGroupTypes[i];
// Default is marine face
AvHMessageID theHotgroupIcon = MENU_SOLDIER_FACE;
AvHSHUUser3ToMessageID(theGroupTypeUser3, theHotgroupIcon);
// Build component name ("PendingImpulseXPanel", where X is the impulse)
AvHMessageID theHotgroupMessageID = theHotgroups[i];
char theComponentName[256];
sprintf(theComponentName, kPendingImpulseSpecifier, (int)theHotgroupMessageID);
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(theComponentName, theTechImpulsePanel))
{
int thePosX, thePosY;
theTechImpulsePanel->getPos(thePosX, thePosY);
int theWidth, theHeight;
theTechImpulsePanel->getSize(theWidth, theHeight);
// Highlight if mouse is in region or if it's our current selection
bool theIsHighlighted = this->GetIsMouseInRegion(thePosX, thePosY, theWidth, theHeight) || (this->mSelected == theHotgroup);
int theFrame = theIsHighlighted ? 1 : 0;
int theSecondOfLastUpdate = (int)this->mTimeOfLastUpdate;
if((this->mGroupAlerts[i] == ALERT_UNDER_ATTACK) && (theSecondOfLastUpdate % 2))
{
// Play blinking red frame when being attacked
theFrame = 3;
}
this->DrawTechTreeSprite(theHotgroupIcon, thePosX, thePosY, theWidth, theHeight, theFrame);
theTechImpulsePanel->SetVisualNumber((int)theHotgroup.size());
}
}
}
}
// Draw pending requests
void AvHHud::DrawPendingRequests()
{
// Run through list of requests and delete any entries with
PendingRequestListType::iterator theIterator;
for(theIterator = this->mPendingRequests.begin(); theIterator != this->mPendingRequests.end(); /* nothing */)
{
if(theIterator->second == 0)
{
PendingRequestListType::iterator theSavedIter = theIterator;
theSavedIter++;
this->mPendingRequests.erase(theIterator);
theIterator = theSavedIter;
}
else
{
theIterator++;
}
}
int theNumRequestsToDraw = (int)this->mPendingRequests.size();
int theCounter = 0;
for(theIterator = this->mPendingRequests.begin(); theIterator != this->mPendingRequests.end(); theIterator++)
{
// Draw each one above the minimap
AvHMessageID theMessageID = theIterator->first;
int theNumRequests = theIterator->second;
// Build component name ("PendingImpulseXPanel", where X is the impulse)
char theComponentName[256];
sprintf(theComponentName, kPendingImpulseSpecifier, (int)theMessageID);
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(theComponentName, theTechImpulsePanel))
{
// Get size of panel and draw tech sprite there
int thePosX, thePosY;
theTechImpulsePanel->getPos(thePosX, thePosY);
int theWidth, theHeight;
theTechImpulsePanel->getSize(theWidth, theHeight);
AvHMessageID theMessageToDraw = theMessageID;
switch(theMessageID)
{
case COMMANDER_NEXTIDLE:
theMessageToDraw = MENU_SOLDIER_FACE;
break;
case COMMANDER_NEXTAMMO:
theMessageToDraw = BUILD_AMMO;
break;
case COMMANDER_NEXTHEALTH:
theMessageToDraw = BUILD_HEALTH;
break;
}
int theFrame = this->GetIsMouseInRegion(thePosX, thePosY, theWidth, theHeight) ? 1 : 0;
this->DrawTechTreeSprite(theMessageToDraw, thePosX, thePosY, theWidth, theHeight, theFrame);
theTechImpulsePanel->SetVisualNumber(theNumRequests);
if(theNumRequests > 0)
{
theTechImpulsePanel->setVisible(true);
}
else
{
theTechImpulsePanel->setVisible(false);
}
//this->DrawHUDNumber(thePosX + kTileWidth, thePosY + kTileHeight, DHN_2DIGITS, theNumRequests);
}
// Draw indicator on sprite showing how many requests there are
theCounter++;
}
}
// tankefugl: 0000988
void AvHHud::DrawBuildHealthEffectsForEntity(int inEntityIndex, float inAlpha)
// :tankefugl
{
// Get entity
int theUser3 = 0;
int theUser4 = 0;
float theFuser1 = 0.0f;
int theEntityTeam = 0;
vec3_t theOrigin;
vec3_t theMins;
vec3_t theMaxs;
bool theContinue = false;
float theHealthPercentage = 0.0f;
double theDistanceToEntity = 0;
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(inEntityIndex);
if(theEntity)
{
theUser3 = theEntity->curstate.iuser3;
theUser4 = theEntity->curstate.iuser4;
theFuser1 = theEntity->curstate.fuser1;
theEntityTeam = theEntity->curstate.team;
//theOrigin = theEntity->curstate.origin;
theOrigin = AvHSHUGetRealLocation(theEntity->origin, theEntity->curstate.mins, theEntity->curstate.maxs);
if(theEntity->player)
{
// Subtract half-height to be at feet
float theHeight = theEntity->curstate.maxs[2] - theEntity->curstate.mins[2];
theOrigin[2] -= theHeight/2.0f;
}
theDistanceToEntity = VectorDistance(gPredictedPlayerOrigin, theOrigin);
theMins = theEntity->curstate.mins;
theMaxs = theEntity->curstate.maxs;
theHealthPercentage = theEntity->curstate.fuser2/kNormalizationNetworkFactor;
theContinue = true;
}
// Get local player
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
bool theDrewBuildInProgress = false;
float theOversizeScalar = 1.0f;
bool theEntityIsPlayer = ((inEntityIndex > 0) && (inEntityIndex <= gEngfuncs.GetMaxClients()));
bool theIsOnOurTeam = (theEntityTeam == (int)this->GetHUDTeam());
if(AvHSHUGetDrawRingsForUser3((AvHUser3)theUser3, theOversizeScalar))
{
if(theContinue && theLocalPlayer)
{
const kDrawEnemyBuildingDistance = 200;
// Draw effects if we are in top-down mode OR
if( this->GetInTopDownMode() ||
// It's an unfriendly building that's very close OR
(!theEntityIsPlayer && (theDistanceToEntity < kDrawEnemyBuildingDistance)) ||
// It's a friendly entity and we're a builder
(theIsOnOurTeam && (this->GetHUDUser3() == AVH_USER3_ALIEN_PLAYER2))
)
{
// If they're not on opposite teams
//if((theEntityTeam == theLocalPlayer->curstate.team) || (theEntityTeam == 0))
//{
// Get entity build/research state
bool theIsBuilding = false;
bool theIsResearching = false;
float theNormalizedPercentage = 0.0f;
// Calculate percentage full
AvHSHUGetBuildResearchState(theUser3, theUser4, theFuser1, theIsBuilding, theIsResearching, theNormalizedPercentage);
bool theDrawHealth = true;
int theSpriteToUse = this->GetIsAlien() ? this->mAlienHealthSprite : this->mMarineHealthSprite;
bool theDrawAsRecyling = (GetHasUpgrade(theUser4, MASK_RECYCLING) && theIsOnOurTeam);
if((theIsBuilding && (GetHasUpgrade(theUser4, MASK_BUILDABLE))) || theDrawAsRecyling)
{
theSpriteToUse = this->GetIsAlien() ? this->mAlienBuildSprite : this->mMarineBuildSprite;
theDrawHealth = false;
// Draw progress inverted, as we're "undoing" the structure
if(theDrawAsRecyling)
{
theNormalizedPercentage = (1.0f - theNormalizedPercentage);
}
}
else
{
theNormalizedPercentage = theHealthPercentage;
}
if(theDrawHealth || (theEntityTeam == theLocalPlayer->curstate.team))
{
// Draw it
int theNumFrames = SPR_Frames(theSpriteToUse);
ASSERT(theNumFrames > 0);
int theCurrentFrame;
if ((theHealthPercentage < 1.0f) || theDrawAsRecyling)
{
theCurrentFrame = theNormalizedPercentage * (theNumFrames - 1);
// tankefugl: 0000893
// quick hack to eliminate 1 red bar shown for dead players
if (theEntity->player)
theCurrentFrame = min(max(0, theCurrentFrame), theNumFrames - 1);
else
theCurrentFrame = min(max(1, theCurrentFrame), theNumFrames - 1);
// :tankefugl
}
else
{
theCurrentFrame = theNumFrames - 1;
}
// Get real position of entity
vec3_t thePosition;
thePosition = AvHSHUGetRealLocation(theOrigin, theMins, theMaxs);
float theMaxX = theMaxs[0] - theMins[0];
float theMaxY = theMaxs[1] - theMins[1];
float theRadius = max(theMaxX, theMaxY)*theOversizeScalar;
// Bring position off ground just a little to prevent z-fighting
thePosition.z += kZFightingOffset;
//GetHasUpgrade(this->GetHUDUpgrades(), MASK_PARASITED)
DrawSpriteOnGroundAtPoint(thePosition, theRadius, theSpriteToUse, kRenderTransAdd, theCurrentFrame, inAlpha);
theDrewBuildInProgress = true;
}
}
}
}
}
void AvHHud::DrawHUDNumber(int inX, int inY, int inFlags, int inNumber)
{
// Draw number on HUD, in our HUD color
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
int theGammaSlope = this->GetGammaSlope();
theR /= theGammaSlope;
theG /= theGammaSlope;
theB /= theGammaSlope;
this->DrawHudNumber(inX, inY, inFlags, inNumber, theR, theG, theB);
}
void AvHHud::DrawSelectionAndBuildEffects()
{
// tankefugl: 0000988
list<int> theSelectedList;
// :tankefugl
// Draw build effects
for(SelectionListType::iterator theSelectIter = this->mSelectionEffects.begin(); theSelectIter != this->mSelectionEffects.end(); theSelectIter++)
{
// Draw selection effect around the entity
int theEntIndex = theSelectIter->mEntIndex;
this->DrawBuildHealthEffectsForEntity(theEntIndex);
// tankefugl: 0000988
theSelectedList.push_back(theEntIndex);
// :tankefugl
}
bool theDrawBuildingEffect = false;
for(EntityListType::iterator theBuildingIter = this->mBuildingEffectsEntityList.begin(); theBuildingIter != this->mBuildingEffectsEntityList.end(); theBuildingIter++)
{
int theEntIndex = *theBuildingIter;
this->DrawBuildHealthEffectsForEntity(theEntIndex);
// tankefugl: 0000988
theSelectedList.push_back(theEntIndex);
// :tankefugl
}
// tankefugl: 0000988
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
gEngfuncs.pEventAPI->EV_PushPMStates();
gEngfuncs.pEventAPI->EV_SetSolidPlayers(-1);
if (this->GetInTopDownMode()) {
int localPlayerIndex = gEngfuncs.GetLocalPlayer()->index;
physent_t *thePlayer = gEngfuncs.pEventAPI->EV_GetPhysent(localPlayerIndex);
// gEngfuncs.Con_Printf("gEngfuncs.GetLocalPlayer()->index = %d, thePlayer->team = %d\n", gEngfuncs.GetLocalPlayer()->index, thePlayer->team);
physent_t* theEntity = NULL;
int theNumEnts = pmove->numphysent;
for (int i = 0; i < theNumEnts; i++)
{
theEntity = gEngfuncs.pEventAPI->EV_GetPhysent(i);
if(theEntity)
{
if (localPlayerIndex != theEntity->info)
{
int theEntityIndex = theEntity->info;
list<int>::iterator theSelectedIterator = find(theSelectedList.begin(), theSelectedList.end(), theEntityIndex);
if (theSelectedIterator == theSelectedList.end())
{
bool theIsPlayer = ((theEntityIndex >= 1) && (theEntityIndex <= gEngfuncs.GetMaxClients()));
bool theSameTeam = (theEntity->team == thePlayer->team );
if(theIsPlayer || theSameTeam)
{
this->DrawBuildHealthEffectsForEntity(theEntityIndex, 0.3);
}
}
}
}
}
}
gEngfuncs.pEventAPI->EV_PopPMStates();
// :tankefugl
}
void AvHHud::Render()
{
if (!IEngineStudio.IsHardware())
{
// Don't show anything in software mode.
const char* theMessage = "Software mode is not supported by Natural Selection";
int theWidth;
int theHeight;
float gammaScale = 1.0f / GetGammaSlope();
gEngfuncs.pfnDrawSetTextColor(0, gammaScale, 0);
gEngfuncs.pfnDrawConsoleStringLen(theMessage, &theWidth, &theHeight);
gEngfuncs.pfnDrawConsoleString((ScreenWidth() - theWidth) / 2, (ScreenHeight() - theHeight) / 2, (char*)theMessage);
return;
}
if (m_Spectator.IsInOverviewMode())
{
AvHSpriteSetViewport(mSpecialViewport[0], mSpecialViewport[1],
mSpecialViewport[0] + mSpecialViewport[2], mSpecialViewport[1] + mSpecialViewport[3]);
}
AvHSpriteBeginFrame();
if (mSteamUIActive)
{
// Use the old 2D method if we're in the Steam UI.
AvHSpriteEnableVGUI(false);
}
else
{
AvHSpriteEnableVGUI(true);
AvHSpriteSetVGUIOffset(0, 0);
}
#ifdef DEBUG
if ( CVAR_GET_FLOAT( "hud_hideview" ) != 0 )
{
// Black out the screen
int sprite = Safe_SPR_Load(kWhiteSprite);
AvHSpriteSetColor(0, 0, 0, 1);
AvHSpriteDraw(sprite, 0, 0, 0, ScreenWidth(), ScreenHeight(), 0, 0, 1, 1);
AvHSpriteSetColor(1, 1, 1, 1);
}
#endif
// Don't draw the HUD while being digested.
if (GetIsBeingDigested())
{
if (this->mDigestingSprite)
{
AvHSpriteSetColor(1,1,1);
AvHSpriteSetRenderMode(kRenderNormal);
DrawWarpedOverlaySprite(mDigestingSprite, 4, 3, .02, .02, .3, .15);
}
}
else
{
if (this->GetHUDPlayMode() == PLAYMODE_PLAYING ||
this->GetHUDPlayMode() == PLAYMODE_READYROOM)
{
if (!mSteamUIActive)
{
this->DrawReticleInfo();
this->DrawPlayerNames();
this->DrawToolTips();
}
}
if (this->GetHUDPlayMode() == PLAYMODE_PLAYING)
{
RenderCommonUI();
if (GetIsMarine())
{
if (GetInTopDownMode())
{
RenderCommanderUI();
}
else
{
RenderMarineUI();
}
}
else if (GetIsAlien())
{
RenderAlienUI();
}
}
}
AvHSpriteEndFrame();
AvHSpriteClearViewport();
}
void AvHHud::RenderCommonUI()
{
if (!mSteamUIActive)
{
if (gHUD.GetServerVariableFloat("sv_cheats") != 0 && CVAR_GET_FLOAT("cl_showspeed") != 0)
{
// Draw the speedometer.
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
extern playermove_s* pmove;
char buffer[1024];
sprintf(buffer, "Speed = %d", (int)Length(pmove->velocity));
mFont.DrawString(10, 10, buffer, theR, theG, theB);
float theGroundSpeed = sqrtf(pmove->velocity[0] * pmove->velocity[0] + pmove->velocity[1] * pmove->velocity[1]);
sprintf(buffer, "Ground speed = %d", (int)theGroundSpeed);
mFont.DrawString(10, 12 + mFont.GetStringHeight(), buffer, theR, theG, theB);
}
DrawInfoLocationText();
DrawHUDStructureNotification();
this->DrawOrders();
this->DrawHelpIcons();
if (this->GetIsCombatMode())
{
// If we're in combat mode, draw our rank
const float kTitleYInset = (kPlayerStatusVerticalInset+5*kPlayerStatusStatusSpacing);
string theTitleText = this->GetRankTitle(true);
char theCharArray[512];
sprintf(theCharArray, theTitleText.c_str());
// Draw it
int theX = mViewport[0] + kPlayerStatusHorizontalCenteredInset*(mViewport[2] - mViewport[0]);
int theY = mViewport[1] + mViewport[3] - (1-kTitleYInset)*ScreenHeight();
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
this->DrawHudStringCentered(theX, theY, ScreenWidth(), theCharArray, theR, theG, theB);
}
// If we're parasited, draw a message as such
if (this->GetIsAlive())
{
string theText;
char theCharArray[512];
int theR, theG, theB;
//UnpackRGB(theR, theG, theB, RGB_YELLOWISH);
this->GetPrimaryHudColor(theR, theG, theB, true, false);
int theSecondOfLastUpdate = (int)this->mTimeOfLastUpdate;
// Draw blinking primal scream message
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_BUFFED) && (theSecondOfLastUpdate % 2))
{
if(this->GetIsAlien())
{
LocalizeString(kPrimalScreamed, theText);
}
else if(this->GetIsMarine())
{
LocalizeString(kCatalysted, theText);
}
// Draw it
sprintf(theCharArray, "%s", theText.c_str());
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), kPlayerStatusVerticalInset*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// Draw parasited indicator
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_PARASITED))
{
LocalizeString(kParasited, theText);
sprintf(theCharArray, "%s", theText.c_str());
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// Draw umbraed indicator
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_UMBRA))
{
LocalizeString(kUmbraed, theText);
sprintf(theCharArray, "%s", theText.c_str());
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+2*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// Draw blinking "webbed" message
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_ENSNARED) && (theSecondOfLastUpdate % 2))
{
LocalizeString(kWebbed, theText);
sprintf(theCharArray, "%s", theText.c_str());
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+3*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// Draw "stunned" message (it's so fast, try not blinking it)
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_PLAYER_STUNNED) /*&& (theSecondOfLastUpdate % 2)*/)
{
LocalizeString(kStunned, theText);
sprintf(theCharArray, "%s", theText.c_str());
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+4*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// Draw "being digested" or "digesting" message
if(this->GetIsBeingDigested() && (theSecondOfLastUpdate % 2))
{
LocalizeString(kDigested, theText);
sprintf(theCharArray, "%s", theText.c_str());
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+5*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
else if(this->GetIsDigesting() && (theSecondOfLastUpdate % 2))
{
// Look up player in progress entity
if((this->mProgressBarEntityIndex >= 1) && (this->mProgressBarEntityIndex <= gEngfuncs.GetMaxClients()))
{
hud_player_info_t thePlayerInfo;
gEngfuncs.pfnGetPlayerInfo(this->mProgressBarEntityIndex, &thePlayerInfo);
char* thePlayerName = thePlayerInfo.name;
if(thePlayerName)
{
LocalizeString(kDigestingPlayer, theText);
sprintf(theCharArray, theText.c_str(), thePlayerName);
}
}
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+5*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
// If we are in a squad, draw it on our HUD
if(this->mCurrentSquad > 0)
{
string theSquadIndicator;
if(LocalizeString(kSquadIndicator, theSquadIndicator))
{
sprintf(theCharArray, theSquadIndicator.c_str(), this->mCurrentSquad);
// Draw it
this->DrawHudStringCentered(kPlayerStatusHorizontalCenteredInset*ScreenWidth(), (kPlayerStatusVerticalInset+6*kPlayerStatusStatusSpacing)*ScreenHeight(), ScreenWidth(), theCharArray, theR, theG, theB);
}
}
}
// Draw the numerical effects.
if(this->GetIsAlive())
{
for(NumericalInfoEffectListType::iterator theIter = this->mNumericalInfoEffects.begin(); theIter != this->mNumericalInfoEffects.end(); theIter++)
{
// Draw it
Vector theScreenPos;
float theWorldPosition[3];
theIter->GetPosition(theWorldPosition);
if(AvHCUWorldToScreen(theWorldPosition, (float*)&theScreenPos))
{
float theNormX = theScreenPos.x/ScreenWidth();
float theNormY = theScreenPos.y/ScreenHeight();
if(!this->GetInTopDownMode() || !this->GetIsRegionBlockedByUI(theNormX, theNormY))
{
float theNumber = theIter->GetNumber();
string thePrependString("+");
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, true, false);
if(theNumber < 0)
{
// Red, minus for negatives
theR = 255;
theG = 0;
theB = 0;
// The "-" is prepended by MakeStringFromInt when negative
thePrependString = string("");
}
const char* thePostPendStringToTranslate = NULL;
string thePostPendString;
switch(theIter->GetEventType())
{
case kNumericalInfoResourcesEvent:
thePostPendStringToTranslate = kNumericalEventResources;
break;
case kNumericalInfoHealthEvent:
thePostPendStringToTranslate = kNumericalEventHealth;
break;
case kNumericalInfoResourcesDonatedEvent:
thePostPendStringToTranslate = kNumericalEventResourcesDonated;
break;
case kNumericalInfoAmmoEvent:
thePostPendStringToTranslate = kNumericalEventAmmo;
break;
}
if(thePostPendStringToTranslate)
{
LocalizeString(thePostPendStringToTranslate, thePostPendString);
}
// Don't draw 0, so we can have other messages
string theNumberString;
if(theNumber != 0)
{
theNumberString = thePrependString + MakeStringFromFloat(theNumber) + " ";
}
string theDisplayString = theNumberString + thePostPendString;
char theCharBuffer[512];
sprintf(theCharBuffer, "%s", theDisplayString.c_str());
this->DrawHudStringCentered(theScreenPos.x, theScreenPos.y, ScreenWidth(), theCharBuffer, theR, theG, theB);
}
}
}
}
}
// Draw the combat HUD.
if (this->GetIsCombatMode())
{
// Now draw our current experience level, so people know how close they are to the next level
// Load alien resource and energy sprites
string theSpriteName = UINameToSprite(kCombatExperienceSprite, ScreenWidth());
int theExperienceSprite = Safe_SPR_Load(theSpriteName.c_str());
if(theExperienceSprite)
{
const float kNormalizedWidth = .1f;
const float kNormalizedYInset = .96f;
const float kNormalizedHeight = .025f;
const int kBaseIndex = this->GetIsMarine() ? 2 : 0;
// Draw full background
const int kXStart = mViewport[0] + (.5f - kNormalizedWidth/2.0f)*(mViewport[2] - mViewport[0]);
const int kYStart = mViewport[1] + mViewport[3] - (1 - kNormalizedYInset)*ScreenHeight();
AvHSpriteSetColor(1,1,1);
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(theExperienceSprite, kBaseIndex + 1, kXStart, kYStart, kXStart + kNormalizedWidth*ScreenWidth(), kYStart + kNormalizedHeight*ScreenHeight(), 0, 0, 1, 1);
// Draw overlay showing amount of experience
float thePercentToNextLevel = AvHPlayerUpgrade::GetPercentToNextLevel(this->GetHUDExperience());
if((thePercentToNextLevel >= 0.0f) && (thePercentToNextLevel <= 1.0f))
{
AvHSpriteDraw(theExperienceSprite, kBaseIndex, kXStart, kYStart, kXStart + thePercentToNextLevel*kNormalizedWidth*ScreenWidth(), kYStart + kNormalizedHeight*ScreenHeight(), 0, 0, thePercentToNextLevel, 1.0f);
}
}
if(this->GetIsAlive(false))
{
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
this->mCombatUpgradeMenu.SetR(theR);
this->mCombatUpgradeMenu.SetG(theG);
this->mCombatUpgradeMenu.SetB(theB);
this->mCombatUpgradeMenu.Draw();
}
}
// Draw top down help
if(this->GetInTopDownMode())
{
this->mTopDownActionButtonHelp.Draw();
}
}
void AvHHud::RenderMiniMap(int inX, int inY, int inWidth, int inHeight)
{
AvHOverviewMap& theOverviewMap = gHUD.GetOverviewMap();
AvHOverviewMap::DrawInfo theDrawInfo;
theDrawInfo.mX = inX;
theDrawInfo.mY = inY;
theDrawInfo.mWidth = inWidth;
theDrawInfo.mHeight = inHeight;
theDrawInfo.mFullScreen = false;
float worldViewWidth = 800.0f;
float aspectRatio = (float)(theDrawInfo.mHeight) / theDrawInfo.mWidth;
float thePlayerX;
float thePlayerY;
theOverviewMap.GetWorldPosition(thePlayerX, thePlayerY);
theDrawInfo.mViewWorldMinX = thePlayerX - worldViewWidth;
theDrawInfo.mViewWorldMinY = thePlayerY - worldViewWidth * aspectRatio;
theDrawInfo.mViewWorldMaxX = thePlayerX + worldViewWidth;
theDrawInfo.mViewWorldMaxY = thePlayerY + worldViewWidth * aspectRatio;
theOverviewMap.Draw(theDrawInfo);
}
void AvHHud::RenderMarineUI()
{
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
if (mMarineTopSprite && (this->mMapMode == MAP_MODE_NS))
{
float theX;
float theY;
float theWidth = .75f*ScreenWidth();
float theHeight = ((float)256/768)*ScreenHeight();
AvHSpriteSetRenderMode(kRenderTransAdd);
AvHSpriteSetColor(1,1,1);
AvHSpriteDrawTiles(mMarineTopSprite, 3, 1, mViewport[2] - theWidth + mViewport[0],
mViewport[1], mViewport[2] + mViewport[0], mViewport[1] + theHeight, 0, 0, 1, 1);
// Draw the minimap.
int theMiniMapX = mViewport[2] - 0.21f * ScreenWidth() + mViewport[0];
int theMiniMapY = mViewport[1] + 0.013 * ScreenHeight();
int theMiniMapWidth = 0.200 * ScreenWidth();
int theMiniMapHeight = 0.202 * ScreenHeight();
RenderMiniMap(theMiniMapX, theMiniMapY, theMiniMapWidth, theMiniMapHeight);
// Draw the resource label.
theHeight = ScreenHeight() * 0.038;
std::string theResourceText;
char theResourceBuffer[64];
LocalizeString(kMarineResourcePrefix, theResourceText);
_snprintf(theResourceBuffer, 64, "%s %d", theResourceText.c_str(), this->mVisualResources);
theX = mViewport[0] + 0.3 * ScreenWidth();
theY = mViewport[1] + 0.007 * ScreenHeight() + (theHeight - GetSmallFont().GetStringHeight()) / 2;
GetSmallFont().DrawString(theX, theY, theResourceBuffer, theR, theG, theB);
// Draw the commander status label.
std::string theCommanderName;
bool theCommanderNameVisible = true;
if (!GetCommanderLabelText(theCommanderName))
{
// Blink if there is no commander.
if ((int)this->mTimeOfLastUpdate % 2)
{
theCommanderNameVisible = false;
}
}
if (theCommanderNameVisible)
{
theX = mViewport[0] + 0.50 * ScreenWidth();
theY = mViewport[1] + 0.006 * ScreenHeight() + (theHeight - GetSmallFont().GetStringHeight()) / 2;
GetSmallFont().DrawString(theX, theY, theCommanderName.c_str(), theR, theG, theB);
}
}
AvHSpriteEnableClippingRect(false);
// TODO: Draw various marine upgrades (assumes 256x256 sprite, with each upgrade being 64x64, listed right to left, top to bottom, armor upgrades first,
// weapon upgrades next, then motion-tracking, then jetpacks, then exoskeleton)
// Do we have a jetpack?
if(GetHasUpgrade(this->GetHUDUpgrades(), MASK_UPGRADE_7))
{
// Draw jetpack energy indicator
if(this->mMarineUIJetpackSprite)
{
float theFactor = 1 - pmove->fuser3/kNormalizationNetworkFactor;
int theFrame = 0;
string theOutputMessage;
if(LocalizeString(kJetpackEnergyHUDText, theOutputMessage))
{
float theX = .9f*ScreenWidth();
float theY = .8f*ScreenHeight();
float theWidth = .02f*ScreenWidth();
float theHeight = .1f*ScreenHeight();
AvHSpriteSetRenderMode(kRenderTransAdd);
AvHSpriteSetColor(1,1,1);
AvHSpriteDraw(mMarineUIJetpackSprite, 0, theX, theY, theX + theWidth, theY + theHeight * theFactor, 0, 0, 1, theFactor);
AvHSpriteDraw(mMarineUIJetpackSprite, 1, theX, theY + theHeight * theFactor, theX + theWidth, theY + theHeight, 0, theFactor, 1, 1);
}
}
}
const int kNumUpgradesToDraw = 4;
AvHUpgradeMask kUpgradeToMaskTable[kNumUpgradesToDraw] = {MASK_UPGRADE_4, MASK_UPGRADE_1, MASK_UPGRADE_8, MASK_UPGRADE_7};
const float kAspectRatio = ScreenWidth()/ScreenHeight();
const float kNormalizedSpacing = 0.01f;
const int kBaseRightOffset = kNormalizedSpacing*ScreenWidth();
const int kVerticalUpgradeSpacing = kNormalizedSpacing*kAspectRatio*ScreenHeight();
int theUpgradeVar = this->GetHUDUpgrades();
const int kUpgradeFrame = 0;
const float kUpgradeSize = 0.05;
int theUpgradeWidth = kUpgradeSize*ScreenWidth();
int theUpgradeHeight = kUpgradeSize*kAspectRatio*ScreenHeight();
for(int i = 0; i < kNumUpgradesToDraw; i++)
{
AvHUpgradeMask theUpgradeMask = kUpgradeToMaskTable[i];
// Draw highest ammo upgrade level
if(theUpgradeMask == MASK_UPGRADE_4)
{
if(GetHasUpgrade(theUpgradeVar, MASK_UPGRADE_5))
{
theUpgradeMask = MASK_UPGRADE_5;
if(GetHasUpgrade(theUpgradeVar, MASK_UPGRADE_6))
{
theUpgradeMask = MASK_UPGRADE_6;
}
}
}
// Draw highest armor level
if(theUpgradeMask == MASK_UPGRADE_1)
{
if(GetHasUpgrade(theUpgradeVar, MASK_UPGRADE_2))
{
theUpgradeMask = MASK_UPGRADE_2;
if(GetHasUpgrade(theUpgradeVar, MASK_UPGRADE_3))
{
theUpgradeMask = MASK_UPGRADE_3;
}
}
}
// Draw heavy armor instead of jetpacks if they have it
if(theUpgradeMask == MASK_UPGRADE_7)
{
if(GetHasUpgrade(theUpgradeVar, MASK_UPGRADE_13))
{
theUpgradeMask = MASK_UPGRADE_13;
}
}
if(GetHasUpgrade(theUpgradeVar, theUpgradeMask))
{
int theFrame = 0;
switch(theUpgradeMask)
{
case MASK_UPGRADE_4:
theFrame = 0;
break;
case MASK_UPGRADE_5:
theFrame = 1;
break;
case MASK_UPGRADE_6:
theFrame = 2;
break;
case MASK_UPGRADE_1:
theFrame = 3;
break;
case MASK_UPGRADE_2:
theFrame = 4;
break;
case MASK_UPGRADE_3:
theFrame = 5;
break;
case MASK_UPGRADE_8:
theFrame = 6;
break;
case MASK_UPGRADE_7:
theFrame = 7;
break;
case MASK_UPGRADE_13:
theFrame = 8;
break;
}
float theStartU = (theFrame % 4)*.25f;
float theStartV = (theFrame / 4)*.333f;
float theEndU = theStartU + .25f;
float theEndV = theStartV + .333f;
const int kBaseX = ScreenWidth() - .05*ScreenWidth();
const int kBaseY = .75*ScreenHeight();
const int kIconWidth = .05*ScreenWidth();
const int kIconHeight = .05*ScreenHeight();
float x1 = kBaseX;
float y1 = kBaseY + i*kIconHeight;
float x2 = x1 + kIconWidth;
float y2 = y1 + kIconHeight;
AvHSpriteSetRenderMode(kRenderTransAdd);
AvHSpriteEnableClippingRect(false);
AvHSpriteSetColor(1, 1, 1, this->GetGammaSlope());
AvHSpriteDraw(mMarineUpgradesSprite, 0, x1, y1, x2, y2, theStartU, theStartV, theEndU, theEndV);
}
}
}
void AvHHud::RenderCommanderUI()
{
RenderStructureRanges();
// Draw command button
if(this->mCommandButtonSprite)
{
// Animate the button unless the mouse is over it (?)
int kNumFrames = 16; // Last frame is highlighted, first frame seems off
const float kFramesPerSecond = 10;
const float kCycleTime = (1.0f/kFramesPerSecond)*kNumFrames;
float theNumCycles = this->mTimeOfLastUpdate/kCycleTime;
int theFrame = 1 + (theNumCycles - (int)theNumCycles)*kNumFrames;
const int kStartX = 890;
int theX = (kStartX/1024.0f)*ScreenWidth();
int theY = (525/768.0f)*ScreenHeight();
float theWidth = ((1024 - kStartX)/1024.0f)*ScreenWidth();
float theHeight = (38/768.0f)*ScreenHeight();
float x1 = theX;
float y1 = theY;
float x2 = x1 + theWidth;
float y2 = y1 + theHeight;
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(mCommandButtonSprite, theFrame, x1, y2, x2, y2, 0, 0, 1, 1);
}
// Draw "select all" button
if(this->mSelectAllSprite)
{
AvHTechImpulsePanel* theTechImpulsePanel = NULL;
if(this->GetManager().GetVGUIComponentNamed(kSelectAllImpulsePanel, theTechImpulsePanel))
{
if(theTechImpulsePanel->isVisible())
{
int theX, theY;
theTechImpulsePanel->getPos(theX, theY);
int theWidth, theHeight;
theTechImpulsePanel->getSize(theWidth, theHeight);
// Draw unhighlighted, highlighted, or active
int theFrame = 0;
// If mouse is over, use frame 1
if(this->GetIsMouseInRegion(theX, theY, theWidth, theHeight))
{
theFrame = 1;
}
// If all troops selected, use frame 2
if((this->mSelected.size()) > 0 && (this->mSelected == this->mSelectAllGroup))
{
theFrame = 2;
}
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(mSelectAllSprite, theFrame, theX, theY, theX + theWidth, theY + theHeight, 0, 0, 1, 1);
}
}
}
// Draw blinking "under attack" indicator
if(this->mCommandStatusSprite)
{
int theFrame = 0;
int theX = (725/1024.0f)*ScreenWidth();
int theY = (702/768.0f)*ScreenHeight();
float theWidth = (61.5f/1024.0f)*ScreenWidth();
float theHeight = (66/768.0f)*ScreenHeight();
// Blink button when an alert is set!
if(this->mBlinkingAlertType)
{
int theSecondOfLastUpdate = (int)this->mTimeOfLastUpdate;
if(theSecondOfLastUpdate % 2)
{
theFrame = this->mBlinkingAlertType;
}
}
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(mCommandStatusSprite, theFrame, theX, theY, theX + theWidth, theY + theHeight, 0, 0, 1, 1);
}
if(this->mTopDownTopSprite)
{
float theHeight = ((float)128/768)*ScreenHeight();
AvHSpriteDrawTiles(mTopDownTopSprite, 4, 1, 0, 0, ScreenWidth(), theHeight, 0, 0, 1, 1);
}
if(this->mTopDownBottomSprite)
{
// The artwork is three 128s high
float theHeight = ((float)256/768)*ScreenHeight();
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDrawTiles(mTopDownBottomSprite, 4, 1, 0, ScreenHeight()-theHeight, ScreenWidth(), ScreenHeight(), 0, 0, 1, 1);
}
// Draw scaled sprites for all ActionButtons
this->DrawActionButtons();
// Draw hotgroups
this->DrawHotgroups();
// Draw pending requests
this->DrawPendingRequests();
// Draw logout button
if(this->mLogoutSprite)
{
int theFrame = 0;
int theX = .785*ScreenWidth();
int theY = .013*ScreenHeight();
float theWidth = .197f*ScreenWidth();
float theHeight = .083f*ScreenHeight();
// Detect mouseover
if(this->GetIsMouseInRegion(theX, theY, theWidth, theHeight))
{
theFrame = 1;
}
AvHSpriteSetRenderMode(kRenderTransAlpha);
AvHSpriteDraw(mLogoutSprite, theFrame, theX, theY, theX + theWidth, theY + theHeight, 0, 0, 1, 1);
}
}
void AvHHud::RenderStructureRanges()
{
float theRangeR = 0;
float theRangeG = 1;
float theRangeB = 0;
float theRangeA = 0.2f;
// Draw range for current ghost building, if applicable
EntityListType theEntities;
IntList theDistanceRequirements;
float theZAdjustment = 0.0f;
bool theSnapToLocation = false;
bool theDrewGhostRegions = false;
AvHSHUGetBuildRegions(this->mGhostBuilding, theEntities, theDistanceRequirements, theZAdjustment, theSnapToLocation);
// For each entity to draw
int theDistanceCounter = 0;
for(EntityListType::iterator theRangeIter = theEntities.begin(); theRangeIter != theEntities.end(); theRangeIter++, theDistanceCounter++)
{
//cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(*theRangeIter);
physent_t* theEntity = gEngfuncs.pEventAPI->EV_GetPhysent(*theRangeIter);
if(theEntity)
{
vec3_t thePosition;
thePosition = AvHSHUGetRealLocation(theEntity->origin, theEntity->mins, theEntity->maxs);
//int theSprite = (theEntity->iuser3 == AVH_USER3_SIEGETURRET) ? this->mSiegeTurretSprite : this->mBuildCircleSprite;
int theSprite = this->mBuildCircleSprite;
int theDistanceRequirement = theDistanceRequirements[theDistanceCounter];
RenderStructureRange(thePosition, theDistanceRequirement, theSprite, kRenderTransAdd, 0, theRangeR, theRangeG, theRangeB, theRangeA);
theDrewGhostRegions = true;
}
}
// Draw selection as well
for(EntityListType::iterator theSelectedIter = this->mSelected.begin(); theSelectedIter != this->mSelected.end(); theSelectedIter++)
{
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(*theSelectedIter);
//physent_t* theEntity = gEngfuncs.pEventAPI->EV_GetPhysent(*theSelectedIter);
if(theEntity)
{
vec3_t thePosition;
thePosition = AvHSHUGetRealLocation(theEntity->curstate.origin, theEntity->curstate.mins, theEntity->curstate.maxs);
AvHUser3 theUser3 = (AvHUser3)(theEntity->curstate.iuser3);
int theRange = AvHSHUGetDrawRangeForUser3(theUser3);
if(theRange > 0)
{
// Don't draw structures that are recycling and therefore inactive
if(!GetHasUpgrade(theEntity->curstate.iuser4, MASK_RECYCLING))
{
//int theSprite = (theEntity->curstate.iuser3 == AVH_USER3_SIEGETURRET) ? this->mSiegeTurretSprite : this->mBuildCircleSprite;
int theSprite = this->mBuildCircleSprite;
RenderStructureRange(thePosition, theRange, theSprite, kRenderTransAdd, 0, theRangeR, theRangeG, theRangeB, theRangeA);
}
}
}
}
// Draw the minimum build radius violations.
EntityListType theBuildViolations;
AvHSHUGetMinBuildRadiusViolations(mGhostBuilding, mGhostWorldLocation, theBuildViolations);
for (EntityListType::iterator theBuildViolationsIter = theBuildViolations.begin(); theBuildViolationsIter != theBuildViolations.end(); ++theBuildViolationsIter)
{
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers (-1);
physent_t* theEntity = gEngfuncs.pEventAPI->EV_GetPhysent(*theBuildViolationsIter);
gEngfuncs.pEventAPI->EV_PopPMStates();
if(theEntity)
{
vec3_t thePosition;
thePosition = AvHSHUGetRealLocation(theEntity->origin, theEntity->mins, theEntity->maxs);
AvHUser3 theUser3 = (AvHUser3)(theEntity->iuser3);
vec3_t theMinSize, theMaxSize;
AvHSHUGetSizeForUser3(theUser3, theMinSize, theMaxSize);
float theMaxRadius2 = max(max(theMinSize.x, theMaxSize.x), max(theMinSize.y, theMaxSize.y));
int theSprite = this->mBuildCircleSprite;
// joev: 0000291
// It's possible to place "on" marines if you're offset a little from center. This code and
// associated changes above and in AvHSharedUtil.cpp is to enforce a build distance around marines,
// in the same way as structures, to prevent this exploit.
float theMinMarineBuildDistance;
if (theUser3 == AVH_USER3_MARINE_PLAYER) {
theMinMarineBuildDistance = BALANCE_VAR(kMinMarinePlayerBuildDistance);
}
else
{
theMinMarineBuildDistance = BALANCE_VAR(kMinMarineBuildDistance);
}
// :joev
RenderStructureRange(thePosition, theMinMarineBuildDistance + theMaxRadius2, theSprite, kRenderTransAdd, 0, 1, 0, 0, 0.3f);
}
}
}
void AvHHud::RenderStructureRange(vec3_t inOrigin, int inRadius, HSPRITE inSprite, int inRenderMode, int inFrame, float inR, float inG, float inB, float inAlpha)
{
vec3_t w1;
w1[0] = inOrigin[0] - inRadius;
w1[1] = inOrigin[1] - inRadius;
w1[2] = inOrigin[2];
vec3_t s1;
gEngfuncs.pTriAPI->WorldToScreen(w1, s1);
vec3_t w2;
w2[0] = inOrigin[0] + inRadius;
w2[1] = inOrigin[1] + inRadius;
w2[2] = inOrigin[2];
vec3_t s2;
gEngfuncs.pTriAPI->WorldToScreen(w2, s2);
float x1 = XPROJECT(s1[0]);
float y1 = YPROJECT(s1[1]);
float x2 = XPROJECT(s2[0]);
float y2 = YPROJECT(s2[1]);
AvHSpriteSetColor(inR, inG, inB, inAlpha);
AvHSpriteSetRenderMode(inRenderMode);
AvHSpriteDraw(inSprite, inFrame, x1, y1, x2, y2, 0, 0, 1, 1);
AvHSpriteSetColor(1, 1, 1, 1);
}
void AvHHud::RenderAlienUI()
{
const float kAspectRatio = ScreenWidth()/ScreenHeight();
// Draw the embryo overlay if the player is gestating.
if (GetHUDUser3() == AVH_USER3_ALIEN_EMBRYO)
{
if (mMembraneSprite)
{
AvHSpriteSetRenderMode(kRenderTransAdd);
AvHSpriteSetColor(1,1,1);
DrawWarpedOverlaySprite(mMembraneSprite, 4, 3, .007 * 2, .002 * 2, .15, .3);
}
return;
}
AvHSpriteSetRenderMode(kRenderTransAlpha);
int theWidth = kResourceEnergyBarWidth*ScreenWidth();
int theHeight = kResourceEnergyBarHeight*ScreenHeight();
int theX = mViewport[0];
int theY = mViewport[3] - theHeight + mViewport[1];
// Draw resource text label.
if (!mSteamUIActive)
{
const float kTextInset = kResourceEnergyBarWidth*.5f;
const int kNumericYOffset = 1.5*this->GetHudStringHeight();
int theResourceLabelX = mViewport[0] + kTextInset*ScreenWidth();
int theResourceLabelY = theY - + .05f * ScreenHeight();
if(this->mMapMode == MAP_MODE_NS)
{
string theLocalizedResourceDescription;
if(LocalizeString(kAlienResourcePrefix, theLocalizedResourceDescription))
{
int theStringWidth = this->GetHudStringWidth(theLocalizedResourceDescription.c_str());
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
this->DrawHudString(theResourceLabelX, theResourceLabelY, ScreenWidth(), theLocalizedResourceDescription.c_str(), theR, theG, theB);
}
// Draw amount we have
char theBuffer[128];
sprintf(theBuffer, "(%d/%d)", this->mVisualResources, this->GetMaxAlienResources());
this->DrawTranslatedString(theResourceLabelX, theResourceLabelY + kNumericYOffset, theBuffer);
}
}
// Draw energy bar.
if (mAlienUIEnergySprite)
{
theX = mViewport[2] - theWidth + mViewport[0];
float theFactor = 1 - this->mVisualEnergyLevel;
AvHSpriteSetColor(1,1,1);
AvHSpriteSetRenderMode(kRenderTransTexture);
AvHSpriteDraw(mAlienUIEnergySprite, 0, theX, theY, theX + theWidth, theY + theHeight * theFactor, 0, 0, 1, theFactor);
AvHSpriteDraw(mAlienUIEnergySprite, 1, theX, theY + theHeight * theFactor, theX + theWidth, theY + theHeight, 0, theFactor, 1, 1);
}
// Draw hive indicators.
if (mHiveInfoSprite) // && (this->mMapMode == MAP_MODE_NS)) // removed check to enable hive with health to be shown in combat
{
int theHiveIndex = 0;
for (HiveInfoListType::iterator theIter = this->mHiveInfoList.begin(); theIter != this->mHiveInfoList.end(); theIter++, theHiveIndex++)
{
// For this hive, figure out which frame to draw
int theFrame = theIter->mStatus;
// If under attack, make it blink red
int theSecondOfLastUpdate = (int)this->mTimeOfLastUpdate;
if(theIter->mUnderAttack && (theSecondOfLastUpdate % 2))
{
theFrame = kHiveInfoStatusUnderAttack;
}
int theHiveWidth = kHiveNormScreenWidth*ScreenWidth();
// Draw hive
//float theNormX = theHiveWidth;
float theNormY = kHiveNormScreenY + kHiveNormScreenVerticalSpacing*theHiveIndex;
//DrawScaledHUDSprite(this->mHiveInfoSprite, kRenderTransAlpha, 1, theNormX*ScreenWidth, theNormY*ScreenHeight(), kHiveNormScreenWidth*ScreenWidth, kHiveNormScreenHeight*ScreenHeight(), theFrame);
float x1 = mViewport[0] + mViewport[2] - theHiveWidth;
float y1 = mViewport[1] + theNormY*ScreenHeight();
float x2 = x1 + theHiveWidth;
float y2 = y1 + kHiveNormScreenHeight*ScreenHeight();
AvHSpriteSetColor(1,1,1);
AvHSpriteSetRenderMode(kRenderTransTexture);
AvHSpriteDraw(mHiveInfoSprite, theFrame, x1, y1, x2, y2, 0, 0, 1, 1);
// AvHSpriteSetColor(1,1,1);
// AvHSpriteSetRenderMode(kRenderTransTexture);
// AvHSpriteDraw(mHiveHealthSprite, 0, x1, y1, x1+100, y1+100, 0, 0, 1, 1);
// use the hive sprite height for the hivehealth sprite height and width
float theHealthSpriteHeight = (float)(kHiveNormScreenHeight) *ScreenHeight();
float theHealthSpriteWidth = theHealthSpriteHeight;
AvHSpriteSetColor(1,1,1);
AvHSpriteSetRenderMode(kRenderTransTexture);
// adjust the position for the sprite -- to the left
float w1 = mViewport[0] + mViewport[2] - (kHiveNormScreenWidth + 0.02f)*ScreenWidth();
AvHSpriteDraw(mHiveHealthSprite, 0, w1, y1, w1 + theHealthSpriteWidth, y1 + theHealthSpriteHeight, 0, 0, 1, 1);
if (theIter->mStatus > 0) {
if (theIter->mHealthPercentage < 100) {
AvHSpriteDraw(mHiveHealthSprite, 0, w1, y1, w1 + theHealthSpriteWidth, y1 + theHealthSpriteHeight, 0, 0, 1, 1);
AvHSpriteDraw(mHiveHealthSprite, 1,
w1, y1 + theHealthSpriteHeight - theHealthSpriteHeight * ((float)(theIter->mHealthPercentage) * 0.92f / 100),
w1 + theHealthSpriteWidth, y1 + theHealthSpriteHeight,
0, 1 - ((float)(theIter->mHealthPercentage) * 0.92f / 100),
1, 1);
} else {
AvHSpriteDraw(mHiveHealthSprite, 1, w1, y1, w1 + theHealthSpriteWidth, y1 + theHealthSpriteHeight, 0, 0, 1, 1);
}
}
// Draw technology it's supporting
AvHMessageID theTechnology = (AvHMessageID)theIter->mTechnology;
theFrame = -1;
switch(theTechnology)
{
case ALIEN_BUILD_DEFENSE_CHAMBER:
theFrame = 0;
break;
case ALIEN_BUILD_SENSORY_CHAMBER:
theFrame = 3;
break;
case ALIEN_BUILD_MOVEMENT_CHAMBER:
theFrame = 2;
break;
}
// Draw it inset
if(theFrame >= 0)
{
float x1 = mViewport[0] + mViewport[2] - theHiveWidth + (kHiveTechnologyInsetXScalar*kHiveNormScreenWidth)*ScreenWidth();
float y1 = mViewport[1] + (theNormY + kHiveTechnologyInsetYScalar*kHiveNormScreenHeight)*ScreenHeight();
float x2 = x1 + kHiveTechnologyInsetWidthScalar*kHiveNormScreenWidth*ScreenWidth();
float y2 = y1 + kHiveTechnologyInsetHeightScalar*kHiveNormScreenHeight*ScreenHeight();
AvHSpriteDraw(mAlienUIUpgradeCategories, theFrame, x1, y1, x2, y2, 0, 0, 1, 1);
}
}
}
// Draw the upgrades.
const int kNumberXInset = 2;
const int kNumberYInset = 2;
const int kBaseYOffset = .1*ScreenHeight();
// Now draw alien upgrades
const float kNormalizedSpacing = 0.01f;
const int kBaseRightOffset = kNormalizedSpacing*ScreenWidth();
const int kVerticalUpgradeSpacing = kNormalizedSpacing*kAspectRatio*ScreenHeight();
int theUpgradeVar = this->GetHUDUpgrades();
const int kUpgradeFrame = 0;
const float kUpgradeSize = 0.05;
int theUpgradeWidth = kUpgradeSize*ScreenWidth();
int theUpgradeHeight = kUpgradeSize*kAspectRatio*ScreenHeight();
// In Combat mode, we can have multiple upgrades in each category
int theNumDrawnInCategory[ALIEN_UPGRADE_CATEGORY_MAX_PLUS_ONE + 1];
memset(theNumDrawnInCategory, 0, sizeof(int)*(ALIEN_UPGRADE_CATEGORY_MAX_PLUS_ONE + 1));
AvHUpgradeMask theUpgradeMasks[kNumAlienUpgrades] = {MASK_UPGRADE_1, MASK_UPGRADE_2, MASK_UPGRADE_3, MASK_NONE, MASK_NONE, MASK_NONE, MASK_UPGRADE_4, MASK_UPGRADE_5, MASK_UPGRADE_6, MASK_UPGRADE_7, MASK_UPGRADE_8, MASK_UPGRADE_9};
for(int i = 0; i < kNumAlienUpgrades; i++)
{
AvHUpgradeMask theUpgradeMask = theUpgradeMasks[i];
AvHAlienUpgradeCategory theCategory = ALIEN_UPGRADE_CATEGORY_INVALID;
AvHGetAlienUpgradeCategoryFromMask(theUpgradeMask, theCategory);
int theCategoryNumber = (int)theCategory;
//int theRowNumber = i % (kNumAlienUpgrades/kNumAlienUpgradeCategories);
// Quick hack: treat defense as offense for drawing purposes, because offense has been (temporarily?) removed
int theCategoryNumberOffset = (int)(((theCategory == ALIEN_UPGRADE_CATEGORY_DEFENSE) ? ALIEN_UPGRADE_CATEGORY_OFFENSE : theCategory));
int theX = ScreenWidth() - theUpgradeWidth - kBaseRightOffset;
// Inset drawing of multiple upgrades in same category (needed for Combat mode)
theX -= (theNumDrawnInCategory[theCategory]*theUpgradeWidth);
int theEnergyHeight = kResourceEnergyBarHeight*ScreenHeight();
int theY = (3*kHiveNormScreenVerticalSpacing)*ScreenHeight() + kVerticalUpgradeSpacing + theCategoryNumberOffset*(kVerticalUpgradeSpacing + theUpgradeHeight);
if(GetHasUpgrade(theUpgradeVar, theUpgradeMask))
{
theNumDrawnInCategory[theCategory]++;
int theLevelOfUpgrade = AvHGetAlienUpgradeLevel(theUpgradeVar, theUpgradeMask);
for(int theLevel = 0; theLevel < theLevelOfUpgrade; theLevel++)
{
// Draw them slightly overlapping
const float kOffset = .01f;
float x1 = theX - theLevel*(kOffset*ScreenWidth());
float y1 = theY - theLevel*(kOffset*ScreenHeight());
float x2 = x1 + theUpgradeWidth;
float y2 = y1 + theUpgradeHeight;
AvHSpriteDraw(mAlienUIUpgrades, i, x1, y1, x2, y2, 0, 0, 1, 1);
}
}
else
{
if(this->GetGameStarted() && !this->GetIsCombatMode())
{
// If upgrade is pending, draw it blinking
for(int i = 0; i < this->mNumUpgradesAvailable; i++)
{
if(this->mCurrentUpgradeCategory[i] == theCategory)
{
int theSecondOfLastUpdate = (int)this->mTimeOfLastUpdate;
if(theSecondOfLastUpdate % 2)
{
int theFrame = theCategory-1;
float x1 = theX;
float y1 = theY;
float x2 = x1 + theUpgradeWidth;
float y2 = y1 + theUpgradeHeight;
AvHSpriteDraw(mAlienUIUpgradeCategories, theFrame, x1, y1, x2, y2, 0, 0, 1, 1);
}
break;
}
}
}
}
}
if(this->GetIsAlien() && (this->GetHUDTeam() != TEAM_IND))
{
bool theIsGestating = (this->GetHUDUser3() == AVH_USER3_ALIEN_EMBRYO);
bool theIsBeingDigested = this->GetIsBeingDigested();
this->mSelectedNodeResourceCost = -1;
// Find the blip nearest our view reticle
int theNearestBlip = -1;
float theDotProductOfClosestBlip = -1;
// Get view vector
Vector theViewVector;
vec3_t theForward, theRight, theUp;
AngleVectors(v_angles, theForward, theRight, theUp);
VectorNormalize(theForward);
for(int theBlip = 0; theBlip < this->mFriendlyBlips.mNumBlips; theBlip++)
{
// Get vector to current blip
Vector theVectorToBlip;
VectorSubtract(this->mFriendlyBlips.mBlipPositions[theBlip], gPredictedPlayerOrigin, theVectorToBlip);
VectorNormalize(theVectorToBlip);
// Dot them
float theDotProduct = DotProduct(theForward, theVectorToBlip);
// Is dot product closer to 1 then best?
if(theDotProduct > theDotProductOfClosestBlip)
{
// Save new blip and dot product
theNearestBlip = theBlip;
theDotProductOfClosestBlip = theDotProduct;
}
}
// Draw information about our friendly blips
theBlip = theNearestBlip;
if(theNearestBlip >= 0)
{
ASSERT(theNearestBlip < this->mFriendlyBlips.mNumBlips);
// Draw location when player under attack
int theBlipStatus = this->mFriendlyBlips.mBlipStatus[theBlip];
//if((theBlipStatus == kVulnerableFriendlyBlipStatus) || ((theBlipStatus >= kSayingOne) && (theBlipStatus <= kSayingSix)))
//{
// Get location
string theLocationName = this->GetNameOfLocation(this->mFriendlyBlips.mBlipPositions[theBlip]);
// Get name of entity
string theBlipName;
int theBlipInfo = this->mFriendlyBlips.mBlipInfo[theBlip];
if(theBlipInfo <= kBaseBlipInfoOffset)
{
hud_player_info_t thePlayerInfo;
gEngfuncs.pfnGetPlayerInfo(theBlipInfo, &thePlayerInfo);
if(thePlayerInfo.name)
{
theBlipName = thePlayerInfo.name;
}
}
else
{
AvHUser3 theUser3 = AvHUser3(theBlipInfo - kBaseBlipInfoOffset);
this->GetTranslatedUser3Name(theUser3, theBlipName);
}
string theBlipStatusText;
char theBlipStatusString[512];
sprintf(theBlipStatusString, "#%s%d", kBlipStatusPrefix, theBlipStatus);
LocalizeString(theBlipStatusString, theBlipStatusText);
Vector theScreenPos;
Vector theMessageWorldPos = this->mFriendlyBlips.mBlipPositions[theBlip];
const float kSpacingScalar = 1.2f;
theMessageWorldPos.z -= (kWorldBlipScale/2.0f)*kSpacingScalar;
if(AvHCUWorldToScreen(theMessageWorldPos, (float*)&theScreenPos))
{
if((theBlipName != "") && (theBlipStatusText != "") && (theLocationName != ""))
{
// "MonsieurEvil is under attack"
// "Resource tower is under attack"
char theFirstLine[512];
sprintf(theFirstLine, "%s %s\n", theBlipName.c_str(), theBlipStatusText.c_str());
this->DrawTranslatedString(theScreenPos[0], theScreenPos[1], theFirstLine, true, true);
char theLocationNameCStr[512];
strcpy(theLocationNameCStr, theLocationName.c_str());
this->DrawTranslatedString(theScreenPos[0], theScreenPos[1] + .022f*ScreenHeight(), theLocationNameCStr, true, true, true);
}
}
//}
}
// Draw hive locations under each hive indicator
if(!theIsGestating && !theIsBeingDigested && (this->mMapMode == MAP_MODE_NS))
{
int theHiveIndex = 0;
for(HiveInfoListType::iterator theIter = this->mHiveInfoList.begin(); theIter != this->mHiveInfoList.end(); theIter++, theHiveIndex++)
{
vec3_t theHivePosition(theIter->mPosX, theIter->mPosY, theIter->mPosZ);
string theLocationName = this->GetNameOfLocation(theHivePosition);
int theHiveWidth = kHiveNormScreenWidth*ScreenWidth();
int theScreenPosX = mViewport[0] + mViewport[2] - theHiveWidth;
int theScreenPosY = mViewport[1] + (kHiveNormScreenY + theHiveIndex*kHiveNormScreenVerticalSpacing + kHiveNormScreenHeight)*ScreenHeight();
string theTranslatedLocationName;
LocalizeString(theLocationName.c_str(), theTranslatedLocationName);
AvHCUTrimExtraneousLocationText(theTranslatedLocationName);
int theR, theG, theB;
this->GetPrimaryHudColor(theR, theG, theB, false, false);
// Draw text in greyscale if hive isn't building or active
if(theIter->mStatus == kHiveInfoStatusUnbuilt)
{
theR = theG = theB = 100;
}
this->DrawHudStringReverse(mViewport[0] + mViewport[2] - 5, theScreenPosY, ScreenWidth(), (char*)theTranslatedLocationName.c_str(), theR, theG, theB);
}
}
}
}
void AvHHud::DrawWarpedOverlaySprite(int spriteHandle, int numXFrames, int numYFrames, float inWarpXAmount, float inWarpYAmount, float inWarpXSpeed, float inWarpYSpeed)
{
float dx = ScreenWidth();
float dy = ScreenHeight();
float theCurrentTime = gHUD.GetTimeOfLastUpdate();
float theNormXAmount = theCurrentTime*inWarpXSpeed - (int)(theCurrentTime*inWarpXSpeed); // Get fractional part of second
float theNormYAmount = theCurrentTime*inWarpYSpeed - (int)(theCurrentTime*inWarpYSpeed);
float theSinusoidalNormXAmount = cos(theNormXAmount*2.0f*M_PI);
float theSinusoidalNormYAmount = sin(theNormYAmount*2.0f*M_PI);
float theXAmount = theSinusoidalNormXAmount*inWarpXAmount;
float theYAmount = theSinusoidalNormYAmount*inWarpYAmount;
for (int frameY = 0; frameY < numYFrames; ++frameY)
{
for (int frameX = 0; frameX < numXFrames; ++frameX)
{
float theWarpXStartAmount = 0;
float theWarpYStartAmount = 0;
float theWarpXEndAmount = 0;
float theWarpYEndAmount = 0;
int frame = frameX + frameY * numXFrames;
float pw = SPR_Width(spriteHandle, frame);
float ph = SPR_Height(spriteHandle, frame);
float fx1 = ((float)(frameX)) / numXFrames;
float fy1 = ((float)(frameY)) / numYFrames;
float fx2 = ((float)(frameX + 1)) / numXFrames;
float fy2 = ((float)(frameY + 1)) / numYFrames;
if(frameX > 0)
{
theWarpXStartAmount = theXAmount*ScreenWidth();
}
if(frameX < numXFrames - 1)
{
theWarpXEndAmount = theXAmount*ScreenWidth();
}
if(frameY > 0)
{
theWarpYStartAmount = theYAmount*ScreenHeight();
}
if(frameY < numYFrames - 1)
{
theWarpYEndAmount = theYAmount*ScreenHeight();
}
AvHSpriteDraw(spriteHandle, frame,
dx * fx1 + theWarpXStartAmount,
dy * fy1 + theWarpYStartAmount,
dx * fx2 + theWarpXEndAmount,
dy * fy2 + theWarpYEndAmount,
1 / pw, 1 / ph, 1 - 1 / pw, 1 - 1 / ph);
}
}
}
void AvHHud::RenderNoZBuffering()
{
if (mSteamUIActive)
{
// Hack since the HUD doesn't get drawn while the Steam UI is open.
Render();
}
// Don't draw this stuff while being digested
if(this->GetIsBeingDigested() || gParticleEditorHandler.GetInEditMode())
{
return;
}
// Temporary, so we can make movies without having the UI flit around (known HL playback bug)
if(/*gEngfuncs.pDemoAPI->IsPlayingback() ||*/ gViewPort->IsOptionsMenuVisible())
{
return;
}
const int theDistance = 50;
const float kAspectRatio = ScreenWidth()/ScreenHeight();
float m_vRenderOrigin[3];
pVector m_vUp;
pVector m_vRight;
pVector m_vNormal;
//vec3_t theViewAngles;
//gEngfuncs.GetViewAngles((float*)theViewAngles)
//gEngfuncs.GetView
IEngineStudio.GetViewInfo( m_vRenderOrigin, (float*)&m_vUp, (float*)&m_vRight, (float*)&m_vNormal );
//float m_fSoftwareXScale, m_fSoftwareYScale;
//IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale );
//vec3_t theViewHeight;
//gEngfuncs.pEventAPI->EV_LocalPlayerViewheight(theViewHeight);
// pVector p;
// p.x = m_vRenderOrigin[0] + m_vNormal.x*theDistance;
// p.y = m_vRenderOrigin[1] + m_vNormal.y*theDistance;
// p.z = m_vRenderOrigin[2] + m_vNormal.z*theDistance;
// pVector p;
// p.x = m_vRenderOrigin[0];
// p.y = m_vRenderOrigin[1];
// p.z = m_vRenderOrigin[2];
// p.x = v_origin[0];
// p.y = v_origin[1];
// p.z = v_origin[2];
// Allow scripts to perform render
AvHScriptManager::Instance()->DrawNoZBuffering();
// if(cl_particleinfo->value)
// {
// // Draw particles here for debugging
// pVector theRealView;
// vec3_t angles, up, right, forward;
// gEngfuncs.pfnAngleVectors(pmove->angles, forward, right, up);
//
// theRealView.x = forward[0];
// theRealView.y = forward[1];
// theRealView.z = forward[2];
//
// AvHParticleSystemManager::Instance()->Draw(theRealView);
// }
//if(this->mMappingTechSprite && !this->mIsRenderingSelectionView && !this->mGameStarted)
//{
// float theXPercentage = 256/1024.0f;
// float theYPercentage = 64/768.0f;
// DrawScaledHUDSprite(this->mMappingTechSprite, kRenderTransColor, 1, 0, ScreenHeight/2, theXPercentage*ScreenWidth, theYPercentage*ScreenHeight());
//}
// Draw blips, orders, selection and build effects for spectators and demo watchers too
int theUpgradeVar = this->GetHUDUpgrades();
bool theHasHiveSightUpgrade = true;//GetHasUpgrade(theUpgradeVar, MASK_ALIEN_UPGRADE_11);
if(this->GetIsAlien())
{
if(theHasHiveSightUpgrade)
{
// Draw friendly blips
this->mFriendlyBlips.Draw(m_vNormal, kFriendlyBlipStatus);
}
}
// Draw enemy blips
this->mEnemyBlips.Draw(m_vNormal, kEnemyBlipStatus);
//this->DrawOrders(true);
this->DrawSelectionAndBuildEffects();
//this->DrawHelpIcons();
}
void AvHHud::VidInit(void)
{
UIHud::VidInit();
mOverviewMap.VidInit();
int theScreenWidth = ScreenWidth();
string theSpriteName;
// theSpriteName = UINameToSprite(kEggSprite, theScreenWidth);
// this->mAlienUIEggSprite = Safe_SPR_Load(theSpriteName.c_str());
// theSpriteName = UINameToSprite(kHiveSprite, theScreenWidth);
// this->mAlienUIHiveSprite = Safe_SPR_Load(theSpriteName.c_str());
int i = 0;
// for(i = 0; i < kNumAlienLifeforms; i++)
// {
// char theBaseName[128];
// sprintf(theBaseName, "%s%d", kLifeformSprite, i+1);
// string theSpriteName = "sprites/level1_hud.spr";//UINameToSprite(theBaseName, theScreenWidth, true);
// this->mAlienUILifeforms[i] = Safe_SPR_Load(theSpriteName.c_str());
// }
char theBaseName[128];
sprintf(theBaseName, "%s", kAlienUpgradeSprite);
theSpriteName = UINameToSprite(theBaseName, theScreenWidth);
this->mAlienUIUpgrades = Safe_SPR_Load(theSpriteName.c_str());
sprintf(theBaseName, "%s", kAlienUpgradeCategory);
theSpriteName = UINameToSprite(theBaseName, theScreenWidth);
this->mAlienUIUpgradeCategories = Safe_SPR_Load(theSpriteName.c_str());
// Load jetpack sprite
theSpriteName = UINameToSprite(kJetpackSprite, theScreenWidth);
this->mMarineUIJetpackSprite = Safe_SPR_Load(theSpriteName.c_str());
// Load alien energy sprite
theSpriteName = UINameToSprite(kAlienEnergySprite, theScreenWidth);
this->mAlienUIEnergySprite = Safe_SPR_Load(theSpriteName.c_str());
// Load background for topdown mode
this->mBackgroundSprite = Safe_SPR_Load(kTopDownBGSprite);
// Load HUD
this->mTopDownTopSprite = Safe_SPR_Load(kTopDownTopHUDSprite);
this->mTopDownBottomSprite = Safe_SPR_Load(kTopDownBottomHUDSprite);
this->mMarineTopSprite = Safe_SPR_Load(kMarineTopHUDSprite);
this->mLogoutSprite = Safe_SPR_Load(kLogoutSprite);
this->mCommandButtonSprite = Safe_SPR_Load(kCommandButtonSprite);
this->mCommandStatusSprite = Safe_SPR_Load(kCommandStatusSprite);
this->mSelectAllSprite = Safe_SPR_Load(kSelectAllSprite);
//this->mTopDownBottomSprite = Safe_SPR_Load("sprites/distorttest.spr");
//this->mTopDownBottomSprite = Safe_SPR_Load("sprites/ns.spr");
//this->mTopDownBottomSprite = Safe_SPR_Load("sprites/distorttest.spr");
// Load overlays
this->mMembraneSprite = Safe_SPR_Load(kMembraneSprite);
this->mDigestingSprite = Safe_SPR_Load(kDigestingSprite);
// Load order sprite
theSpriteName = UINameToSprite(kOrdersSprite, theScreenWidth);
this->mOrderSprite = Safe_SPR_Load(theSpriteName.c_str());
this->mHiveInfoSprite = Safe_SPR_Load(kHiveInfoSprite);
this->mHiveHealthSprite = Safe_SPR_Load(kHiveHealthSprite);
// Load cursor sprite
this->mMarineCursor = Safe_SPR_Load(kCursorsSprite);
this->mAlienCursor = Safe_SPR_Load(kAlienCursorSprite);
this->mMarineOrderIndicator = Safe_SPR_Load(kMarineOrderSprite);
this->mMarineUpgradesSprite = Safe_SPR_Load(kMarineUpgradesSprite);
//this->mMappingTechSprite = Safe_SPR_Load("sprites/ns.spr");
this->mAlienBuildSprite = Safe_SPR_Load(kAlienBuildSprite);
this->mMarineBuildSprite = Safe_SPR_Load(kMarineBuildSprite);
this->mAlienHealthSprite = Safe_SPR_Load(kAlienHealthSprite);
this->mMarineHealthSprite = Safe_SPR_Load(kMarineHealthSprite);
this->mBuildCircleSprite = Safe_SPR_Load(kBuildCircleSprite);
//this->mSiegeTurretSprite = Safe_SPR_Load(kSiegeTurretSprite);
this->mActionButtonSprites.clear();
//this->mHelpSprites.clear();
string theIconName = string(kHelpIconPrefix) + ".spr";
this->mHelpSprite = Safe_SPR_Load(theIconName.c_str());
this->mEnemyBlips.VidInit();
this->mFriendlyBlips.VidInit();
}