mirror of
https://github.com/ENSL/NS.git
synced 2024-11-23 13:02:12 +00:00
4586 lines
149 KiB
C++
4586 lines
149 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 "AvHHud.h"
|
|
#include "cl_dll/hud.h"
|
|
#include "cl_dll/cl_util.h"
|
|
#include "AvHConstants.h"
|
|
#include "AvHClientVariables.h"
|
|
#include "AvHSpecials.h"
|
|
#include "../common/cl_entity.h"
|
|
#include "AvHTitles.h"
|
|
#include "../pm_shared/pm_debug.h"
|
|
#include "../util/MathUtil.h"
|
|
#include "../common/r_efx.h"
|
|
#include "cl_dll/eventscripts.h"
|
|
#include "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 "AvHMiniMap.h"
|
|
#include "AvHActionButtons.h"
|
|
#include "../util/STLUtil.h"
|
|
#include "AvHSharedUtil.h"
|
|
#include "../common/event_api.h"
|
|
#include "AvHScriptManager.h"
|
|
#include <p_vector.h>
|
|
#include <papi.h>
|
|
#include "AvHParticleSystemManager.h"
|
|
#include "AvHTeamHierarchy.h"
|
|
#include "AvHClientUtil.h"
|
|
#include "AvHTooltip.h"
|
|
#include "cl_dll/demo.h"
|
|
#include "../common/demo_api.h"
|
|
#include "AvHHudConstants.h"
|
|
#include "AvHPlayerUpgrade.h"
|
|
#include "AvHCommanderModeHandler.h"
|
|
#include "../common/ref_params.h"
|
|
#include "AvHTechImpulsePanel.h"
|
|
#include "AvHServerVariables.h"
|
|
#include "AvHSpriteAPI.h"
|
|
#include "AvHParticleEditorHandler.h"
|
|
#include "AvHAlienAbilityConstants.h"
|
|
#include <list>
|
|
#include "../common/entity_types.h"
|
|
|
|
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, float alpha)
|
|
{
|
|
// 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());
|
|
|
|
theR *= alpha;
|
|
theB *= alpha;
|
|
theG *= alpha;
|
|
|
|
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(AVHHSPRITE 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, AVHHSPRITE 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, AVHHSPRITE 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(AVHHSPRITE inSpriteHandle, int inRenderMode, vec3_t inWorldPosition, int inFrame, float inWorldSize, float inAlpha)
|
|
// : added inAlpha
|
|
{
|
|
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, inAlpha);
|
|
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);
|
|
|
|
}
|
|
|
|
vec3_t orderDir;
|
|
inOrder.GetLocation(orderDir);
|
|
this->GetOrderDirection(orderDir, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
// : 0000992
|
|
string theFirstLine = theLocalizedTitle;
|
|
if(theRangeDisplayString != "")
|
|
{
|
|
theFirstLine += string(" : ") + theRangeDisplayString;
|
|
}
|
|
// :
|
|
|
|
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);
|
|
}
|
|
}
|
|
// : 0000992
|
|
if (this->mDisplayOrderType == 2)
|
|
{
|
|
// this->mDisplayOrderText1 = "The commander issued an order:";
|
|
this->mDisplayOrderText1 = theFirstLine.c_str();
|
|
this->mDisplayOrderText2 = theTranslatedLocation.c_str();
|
|
}
|
|
// :
|
|
}
|
|
|
|
// :
|
|
#define CENTER_TEXT_LENGTH 10
|
|
#define CENTER_TEXT_FADEOUT 2
|
|
void AvHHud::DrawCenterText()
|
|
{
|
|
if ((this->mCenterTextTime > -1) && (this->mTimeOfLastUpdate < this->mCenterTextTime + CENTER_TEXT_LENGTH + CENTER_TEXT_FADEOUT))
|
|
{
|
|
int theR, theG, theB;
|
|
this->GetPrimaryHudColor(theR, theG, theB, false, false);
|
|
|
|
if (this->mTimeOfLastUpdate > this->mCenterTextTime + CENTER_TEXT_LENGTH)
|
|
{
|
|
float fraction = this->mTimeOfLastUpdate - (this->mCenterTextTime + CENTER_TEXT_LENGTH);
|
|
fraction = 1 - fraction / CENTER_TEXT_FADEOUT;
|
|
theR *= fraction;
|
|
theG *= fraction;
|
|
theB *= fraction;
|
|
}
|
|
|
|
int posX = 0.5 * ScreenWidth() - this->mFont.GetStringWidth(this->mCenterText.c_str()) / 2;
|
|
int posY = 0.4 * ScreenHeight();
|
|
|
|
this->mFont.DrawString(posX, posY, this->mCenterText.c_str(), theR, theG, theB);
|
|
}
|
|
}
|
|
// :
|
|
|
|
// : 0000992
|
|
void AvHHud::SetDisplayOrder(int inOrderType, int inOrderIndex, string inText1, string inText2, string inText3)
|
|
{
|
|
this->mDisplayOrderTime = this->mTimeOfLastUpdate;
|
|
this->mDisplayOrderType = inOrderType;
|
|
this->mDisplayOrderIndex = inOrderIndex;
|
|
this->mDisplayOrderText1 = inText1;
|
|
this->mDisplayOrderText2 = inText2;
|
|
this->mDisplayOrderText3 = inText3;
|
|
}
|
|
|
|
void AvHHud::DrawDisplayOrder()
|
|
{
|
|
const float flashLength = 1.0f;
|
|
const float fadeLimit = 6.0f;
|
|
const float fadeEnd = 2.0f;
|
|
|
|
if ((this->mDisplayOrderType > 0) && (this->mDisplayOrderTime + fadeLimit + fadeEnd) > this->mTimeOfLastUpdate && (this->GetInTopDownMode() == false))
|
|
{
|
|
float theFade = 1.0f;
|
|
if ((this->mDisplayOrderTime + fadeLimit) < this->mTimeOfLastUpdate)
|
|
{
|
|
theFade = 1.0f - (this->mTimeOfLastUpdate - (this->mDisplayOrderTime + fadeLimit)) / fadeEnd;
|
|
if(theFade < 0.0f)
|
|
{
|
|
this->mDisplayOrderType = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// flash the icon for the first second
|
|
if ((this->mDisplayOrderTime + flashLength) > this->mTimeOfLastUpdate)
|
|
{
|
|
if (((int)((this->mTimeOfLastUpdate - this->mDisplayOrderTime) * 8)) % 2)
|
|
{
|
|
theFade = 0.0f;
|
|
}
|
|
}
|
|
|
|
// draw the panel
|
|
// int sprite = SPR_Load(kWhiteSprite);
|
|
|
|
int r, g, b;
|
|
GetPrimaryHudColor(r, g, b, true, false);
|
|
|
|
int theStringHeight = this->GetHudStringHeight();
|
|
|
|
float mIconX1 = 0.47f * ScreenWidth();
|
|
float mIconY1 = 0.10f * ScreenHeight();
|
|
float mIconX2 = mIconX1 + 0.06f * ScreenWidth();
|
|
float mIconY2 = mIconY1 + 0.06f * ScreenWidth();
|
|
float mLeftX = mIconX1 - 0.06f * ScreenWidth();
|
|
float mRightX = mIconX2 + 0.06f * ScreenWidth();
|
|
|
|
float mTextX1 = 0.50f * ScreenWidth();
|
|
|
|
AvHSpriteSetRenderMode(kRenderTransAdd);
|
|
AvHSpriteSetDrawMode(kSpriteDrawModeFilled);
|
|
AvHSpriteSetColor(1, 1, 1, 1 * theFade);
|
|
|
|
int theTeamAdd = 0;
|
|
if (this->GetIsAlien())
|
|
theTeamAdd = 2;
|
|
|
|
if (this->mDisplayOrderDirection == 1)
|
|
AvHSpriteDraw(this->mTeammateOrderSprite, TEAMMATE_MARINE_LEFT_ARROW + theTeamAdd,
|
|
mLeftX, mIconY1, mIconX1, mIconY2, 0, 0, 1, 1); // Left
|
|
else if (this->mDisplayOrderDirection == 2)
|
|
AvHSpriteDraw(this->mTeammateOrderSprite, TEAMMATE_MARINE_RIGHT_ARROW + theTeamAdd,
|
|
mIconX2, mIconY1, mRightX, mIconY2, 0, 0, 1, 1); // Right
|
|
|
|
if (this->mDisplayOrderType == 1)
|
|
{
|
|
AvHSpriteDraw(this->mTeammateOrderSprite, this->mDisplayOrderIndex + 8, mIconX1, mIconY1, mIconX2, mIconY2, 0, 0, 1, 1);
|
|
this->DrawHudStringCentered(mTextX1, mIconY2, ScreenWidth(), this->mDisplayOrderText1.c_str(), r, g, b);
|
|
}
|
|
else if (this->mDisplayOrderType == 2)
|
|
{
|
|
AvHSpriteDraw(this->mOrderSprite, this->mDisplayOrderIndex, mIconX1, mIconY1, mIconX2, mIconY2, 0, 0, 1, 1);
|
|
this->DrawHudStringCentered(mTextX1, mIconY2, ScreenWidth(), this->mDisplayOrderText1.c_str(), r, g, b);
|
|
this->DrawHudStringCentered(mTextX1, mIconY2 + theStringHeight, ScreenWidth(), this->mDisplayOrderText2.c_str(), r, g, b);
|
|
}
|
|
|
|
// float mTextX1 = mIconX2 + 0.02 * ScreenWidth();
|
|
// this->DrawHudString(mTextX1, mIconY1, ScreenWidth(), this->mDisplayOrderText1.c_str(), r, g, b);
|
|
// this->DrawHudString(mTextX1, mIconY1 + theStringHeight, ScreenWidth(), this->mDisplayOrderText2.c_str(), r, g, b);
|
|
// this->DrawHudString(mTextX1, mIconY1 + theStringHeight * 2, ScreenWidth(), this->mDisplayOrderText3.c_str(), r, g, b);
|
|
}
|
|
}
|
|
// :
|
|
|
|
// : 0000971
|
|
void AvHHud::GetOrderDirection(vec3_t inTarget, int inOrderType)
|
|
{
|
|
if (this->mDisplayOrderType == inOrderType)
|
|
{
|
|
// find left/right/none direction for the order popup notificator
|
|
vec3_t theForward, theRight, theUp, theDir;
|
|
AngleVectors(v_angles, theForward, theRight, theUp);
|
|
VectorSubtract(inTarget, v_origin, theDir);
|
|
theForward[2] = theDir[2] = 0;
|
|
VectorNormalize(theForward);
|
|
VectorNormalize(theDir);
|
|
|
|
this->mDisplayOrderDirection = 0;
|
|
// if it is too close to screen center, ignore it
|
|
if (DotProduct(theForward, theDir) < 0.9f)
|
|
{
|
|
// Determine left and right
|
|
vec3_t theCrossProd = CrossProduct(theForward, theDir);
|
|
if (theCrossProd[2] > 0.0f)
|
|
this->mDisplayOrderDirection = 1; // Left
|
|
else if (theCrossProd[2] < 0.0f)
|
|
this->mDisplayOrderDirection = 2; // Right
|
|
}
|
|
}
|
|
}
|
|
|
|
void AvHHud::DrawTeammateOrders()
|
|
{
|
|
|
|
TeammateOrderListType::iterator toErase = this->mTeammateOrder.end();// to fix 2014 not sure wether it works correctly or not was NULL BEFORE
|
|
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
|
|
|
|
const float flashLength = 1.0f;
|
|
const float fadeLimit = 6.0f;
|
|
const float fadeEnd = 2.0f;
|
|
|
|
for(TeammateOrderListType::iterator theIter = this->mTeammateOrder.begin(); theIter != this->mTeammateOrder.end(); theIter++)
|
|
{
|
|
float lastOrder = 0;
|
|
TeammateOrderType theOrder = (*theIter).second;
|
|
int theEntIndex = (*theIter).first;
|
|
float theFade = 1.0f;
|
|
|
|
// remove the order if it has expired
|
|
if((theOrder.second + fadeEnd + fadeLimit) < this->mTimeOfLastUpdate)
|
|
{
|
|
toErase = theIter;
|
|
continue;
|
|
}
|
|
// draw the order fading away
|
|
else if((theOrder.second + fadeLimit) < this->mTimeOfLastUpdate)
|
|
{
|
|
theFade = 1.0f - (this->mTimeOfLastUpdate - (theOrder.second + fadeLimit)) / fadeEnd;
|
|
if(theFade < 0.0f)
|
|
theFade = 0.0f;
|
|
}
|
|
// else, draw the order normally
|
|
|
|
cl_entity_s* theEntity = gEngfuncs.GetEntityByIndex(theEntIndex);
|
|
if (theEntity && (theEntIndex < MAX_PLAYERS && theEntIndex >= 0) && (theEntity->index != theLocalPlayer->index))
|
|
{
|
|
if (AvHTraceLineAgainstWorld(theLocalPlayer->origin, theEntity->origin) == 1.0f)
|
|
{
|
|
vec3_t theVec;
|
|
VectorCopy(theEntity->origin, theVec);
|
|
theVec[2] += AvHCUGetIconHeightForPlayer((AvHUser3)theEntity->curstate.iuser3);
|
|
this->DrawWorldSprite(this->mTeammateOrderSprite, kRenderTransAdd, theVec, theOrder.first, kHelpIconDrawSize, theFade);
|
|
|
|
if (lastOrder < theOrder.second)
|
|
{
|
|
lastOrder = theOrder.second;
|
|
this->GetOrderDirection(theVec, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toErase != this->mTeammateOrder.end()) // to fix 2014 not sure wether it works correctly or not was NULL BEFORE
|
|
this->mTeammateOrder.erase(toErase);
|
|
|
|
// flash target player
|
|
if (((this->mCurrentOrderTime + flashLength) > this->mTimeOfLastUpdate) && (this->mCurrentOrderTarget > 0))
|
|
{
|
|
if (((int)((this->mTimeOfLastUpdate - (this->mCurrentOrderTime + flashLength)) * 8)) % 2)
|
|
{
|
|
cl_entity_s* theTargetEntity = gEngfuncs.GetEntityByIndex(this->mCurrentOrderTarget);
|
|
|
|
vec3_t theVec;
|
|
VectorCopy(theTargetEntity->origin, theVec);
|
|
theVec[2] += AvHCUGetIconHeightForPlayer((AvHUser3)theTargetEntity->curstate.iuser3);
|
|
this->DrawWorldSprite(this->mTeammateOrderSprite, kRenderTransAdd, theVec, this->mCurrentOrderType, kHelpIconDrawSize, 1.0f);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
// :
|
|
|
|
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)
|
|
{
|
|
//: 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;
|
|
}
|
|
|
|
AVHHSPRITE 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] = 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 = .01f;
|
|
const float kHUDStructureNotificationStartY = .08f;
|
|
const float kHUDStructureNotificationIconWidth = .03f;
|
|
const float kHUDStructureNotificationIconHeight = kHUDStructureNotificationIconWidth*1.333f;
|
|
const float kHUDStructureNotificationIconHorizontalSpacing = .01f;
|
|
const float kHUDStructureNotificationIconVerticalSpacing = kHUDStructureNotificationIconHorizontalSpacing*1.333f;
|
|
//const float kHUDStructureNotificationMaxTextWidth = .2f;
|
|
const float kTextHeightCenteringFactor = 0.25f;
|
|
|
|
// Draw them all in order
|
|
if(this->GetIsAlive() && CVAR_GET_FLOAT(kvBuildMessages))
|
|
{
|
|
// Get starting coords
|
|
float theCurrentX = kHUDStructureNotificationStartX;
|
|
float theCurrentY = kHUDStructureNotificationStartY;
|
|
|
|
bool isMarine = GetIsMarine();
|
|
float kSmallScaleFactor;
|
|
//Don't make building icons smaller if alien.
|
|
(isMarine) ? kSmallScaleFactor = 0.75f : kSmallScaleFactor = 1.0f;
|
|
const float kIconWidthSmall = kHUDStructureNotificationIconWidth * kSmallScaleFactor;
|
|
const float kIconHeightSmall = kHUDStructureNotificationIconHeight * kSmallScaleFactor;
|
|
|
|
if (isMarine)
|
|
{
|
|
for (ResearchInfoListType::iterator theIter = this->mResearchInfoList.begin(); theIter != this->mResearchInfoList.end(); theIter++)
|
|
{
|
|
// Draw icon
|
|
AvHMessageID theIconTech = theIter->mResearch;
|
|
int theFrame = 0;
|
|
int theStartX = (theCurrentX + kHUDStructureNotificationIconWidth + kHUDStructureNotificationIconHorizontalSpacing)*ScreenWidth();
|
|
|
|
string theResearchTimerText;
|
|
ActionButton::GetLabelForMessage(theIconTech, theResearchTimerText);
|
|
|
|
int timeLeft = theIter->mTimeResearchDone - this->mTimeOfCurrentUpdate;
|
|
int theMinutesLeft = timeLeft / 60;
|
|
int theSecondsLeft = timeLeft % 60;
|
|
|
|
if (theMinutesLeft)
|
|
theResearchTimerText += " - " + MakeStringFromInt(theMinutesLeft) + "m " + MakeStringFromInt(theSecondsLeft) + "s";
|
|
else
|
|
theResearchTimerText += " - " + MakeStringFromInt(theSecondsLeft) + "s";
|
|
|
|
int theR, theG, theB;
|
|
this->GetPrimaryHudColor(theR, theG, theB, true, false);
|
|
char theCharBuffer[512];
|
|
sprintf(theCharBuffer, "%s", theResearchTimerText.c_str());
|
|
|
|
float theCurrentTextY = theCurrentY + (kHUDStructureNotificationIconHeight * kTextHeightCenteringFactor);
|
|
|
|
this->DrawTechTreeSprite(theIconTech, theCurrentX*ScreenWidth(), theCurrentY*ScreenHeight(), kHUDStructureNotificationIconWidth*ScreenWidth(), kHUDStructureNotificationIconHeight*ScreenHeight(), theFrame);
|
|
this->DrawHudString(theStartX, theCurrentTextY*ScreenHeight(), ScreenWidth(), theCharBuffer, theR, theG, theB);
|
|
|
|
theCurrentY += (kHUDStructureNotificationIconHeight + kHUDStructureNotificationIconVerticalSpacing);
|
|
}
|
|
}
|
|
|
|
for(StructureHUDNotificationListType::iterator theIter = this->mStructureNotificationList.begin(); theIter != this->mStructureNotificationList.end(); theIter++)
|
|
{
|
|
// Draw icon
|
|
AvHMessageID theIconTech = theIter->mStructureID;
|
|
int theFrame = 0;
|
|
string theLocationName = this->GetNameOfLocation(theIter->mLocation);
|
|
int theStartX = (theCurrentX + kHUDStructureNotificationIconWidth + kHUDStructureNotificationIconHorizontalSpacing)*ScreenWidth();
|
|
bool isResearch = AvHSHUGetIsResearchTech(theIconTech);
|
|
|
|
if (!isResearch)
|
|
{
|
|
this->DrawTechTreeSprite(theIconTech, theCurrentX*ScreenWidth(), theCurrentY*ScreenHeight(), kIconWidthSmall*ScreenWidth(), kIconHeightSmall*ScreenHeight(), theFrame);
|
|
if (theLocationName != "")
|
|
{
|
|
int theStartXsmall = theStartX * kSmallScaleFactor;
|
|
float theCurrentTextY = theCurrentY + (kIconHeightSmall * kTextHeightCenteringFactor);
|
|
this->DrawTranslatedString(theStartXsmall, theCurrentTextY*ScreenHeight(), theLocationName.c_str(), false, true);
|
|
}
|
|
|
|
// Increment coords
|
|
theCurrentY += (kIconHeightSmall + 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()) )
|
|
{
|
|
|
|
AVHHSPRITE 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)
|
|
{
|
|
|
|
AVHHSPRITE sprite = 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 = 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 = 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AVHHSPRITE 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;
|
|
if (CVAR_GET_FLOAT("hud_style") == 2.0f)
|
|
theSpriteName = kTechTreeSpriteDirectoryNL + string("/") + kTechTreeSpritePrefix + string(theMessageNumberString) + string("s.spr");
|
|
else
|
|
theSpriteName = kTechTreeSpriteDirectory + string("/") + kTechTreeSpritePrefix + string(theMessageNumberString) + string("s.spr");
|
|
AVHHSPRITE theSpriteHandle = 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
|
|
AVHHSPRITE 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;
|
|
AVHHSPRITE 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++;
|
|
}
|
|
}
|
|
|
|
|
|
// : 0000988
|
|
void AvHHud::DrawBuildHealthEffectsForEntity(int inEntityIndex, float inAlpha)
|
|
// :
|
|
{
|
|
if ( this->GetHUDPlayMode() == PLAYMODE_READYROOM )
|
|
return;
|
|
|
|
// Get entity
|
|
int theUser3 = 0;
|
|
int theUser4 = 0;
|
|
float theFuser1 = 0.0f;
|
|
int theEntityTeam = 0;
|
|
bool theIsOnOurTeam=false;
|
|
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);
|
|
bool theEntityIsPlayer = ((inEntityIndex > 0) && (inEntityIndex <= gEngfuncs.GetMaxClients()));
|
|
|
|
if(theEntity)
|
|
{
|
|
theUser3 = theEntity->curstate.iuser3;
|
|
theUser4 = theEntity->curstate.iuser4;
|
|
theFuser1 = theEntity->curstate.fuser1;
|
|
theEntityTeam = theEntity->curstate.team;
|
|
theIsOnOurTeam = (theEntityTeam == (int)this->GetHUDTeam());
|
|
//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;
|
|
// : 991 transmit armour and health for marines
|
|
if ( GetIsMarine() && theEntityIsPlayer && theIsOnOurTeam ) {
|
|
int tmpPercent=theEntity->curstate.fuser2;
|
|
if ( GetInTopDownMode() ) {
|
|
theHealthPercentage = (float)(tmpPercent&0x7F)/100;
|
|
}
|
|
else {
|
|
theHealthPercentage = (float)(tmpPercent >> 7)/100;
|
|
}
|
|
}
|
|
// :
|
|
theContinue = true;
|
|
|
|
// 991:
|
|
// Do not display health rings for enemy players unless we are commander
|
|
if ( !GetInTopDownMode() && theEntityIsPlayer && !theIsOnOurTeam ) {
|
|
theContinue=false;
|
|
}
|
|
}
|
|
|
|
// Get local player
|
|
cl_entity_s* theLocalPlayer = gEngfuncs.GetLocalPlayer();
|
|
|
|
bool theDrewBuildInProgress = false;
|
|
float theOversizeScalar = 1.0f;
|
|
|
|
if(AvHSHUGetDrawRingsForUser3((AvHUser3)theUser3, theOversizeScalar))
|
|
{
|
|
if(theContinue && theLocalPlayer)
|
|
{
|
|
const int 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 OR
|
|
(theIsOnOurTeam && (this->GetHUDUser3() == AVH_USER3_ALIEN_PLAYER2)) ||
|
|
|
|
// It's a friendly player with <95% armor and we have a welder in our inventory OR
|
|
(theIsOnOurTeam && theEntityIsPlayer && theHealthPercentage < 0.95f && this->mHasWelder) ||
|
|
|
|
// welder/healing spray is selected
|
|
(this->mCurrentWeaponID == 18 || this->mCurrentWeaponID == 27)
|
|
|
|
)
|
|
{
|
|
|
|
// 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;
|
|
AVHHSPRITE theSpriteToUse = this->GetIsAlien() ? this->mAlienHealthSprite : this->mMarineHealthSprite;
|
|
bool theDrawAsRecyling = (GetHasUpgrade(theUser4, MASK_RECYCLING) && theIsOnOurTeam);
|
|
|
|
if((theIsOnOurTeam && 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);
|
|
// : 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);
|
|
// :
|
|
}
|
|
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()
|
|
{
|
|
// : 0000988
|
|
list<int> theSelectedList;
|
|
// :
|
|
|
|
// 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);
|
|
// : 0000988
|
|
theSelectedList.push_back(theEntIndex);
|
|
// :
|
|
}
|
|
|
|
bool theDrawBuildingEffect = false;
|
|
|
|
for(EntityListType::iterator theBuildingIter = this->mBuildingEffectsEntityList.begin(); theBuildingIter != this->mBuildingEffectsEntityList.end(); theBuildingIter++)
|
|
{
|
|
int theEntIndex = *theBuildingIter;
|
|
this->DrawBuildHealthEffectsForEntity(theEntIndex);
|
|
// : 0000988
|
|
theSelectedList.push_back(theEntIndex);
|
|
// :
|
|
}
|
|
|
|
// : 0000988 & 0000991
|
|
bool maintanceWeaponSelected = (this->mCurrentWeaponID == 18 || this->mCurrentWeaponID == 27);
|
|
bool isCommander = this->GetInTopDownMode();
|
|
if (isCommander || maintanceWeaponSelected) {
|
|
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
|
|
gEngfuncs.pEventAPI->EV_PushPMStates();
|
|
gEngfuncs.pEventAPI->EV_SetSolidPlayers(-1);
|
|
|
|
int localPlayerIndex = gEngfuncs.GetLocalPlayer()->index;
|
|
int currentteam = this->GetHUDTeam();
|
|
int maxclients = gEngfuncs.GetMaxClients();
|
|
|
|
|
|
int theNumEnts = pmove->numphysent;
|
|
physent_t* theEntity = NULL;
|
|
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 <= maxclients));
|
|
bool theSameTeam = (theEntity->team == currentteam );
|
|
if (isCommander && (theIsPlayer || theSameTeam))
|
|
{
|
|
this->DrawBuildHealthEffectsForEntity(theEntityIndex, 0.2);
|
|
}
|
|
else if (maintanceWeaponSelected && theSameTeam && !theIsPlayer)
|
|
{
|
|
if (AvHTraceLineAgainstWorld(gEngfuncs.GetLocalPlayer()->origin, theEntity->origin) == 1.0f)
|
|
{
|
|
this->DrawBuildHealthEffectsForEntity(theEntityIndex, 0.3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
gEngfuncs.pEventAPI->EV_PopPMStates();
|
|
}
|
|
// :
|
|
}
|
|
|
|
|
|
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 = 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);
|
|
}
|
|
|
|
RenderProgressBar(kProgressBarSprite);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (this->GetHUDPlayMode() == PLAYMODE_PLAYING ||
|
|
this->GetHUDPlayMode() == PLAYMODE_READYROOM)
|
|
{
|
|
|
|
if (!mSteamUIActive)
|
|
{
|
|
this->DrawReticleInfo();
|
|
this->DrawPlayerNames();
|
|
this->DrawToolTips();
|
|
this->DrawCenterText();
|
|
}
|
|
|
|
}
|
|
|
|
if (this->GetHUDPlayMode() == PLAYMODE_PLAYING)
|
|
{
|
|
|
|
RenderCommonUI();
|
|
|
|
if (GetIsMarine())
|
|
{
|
|
if (GetInTopDownMode())
|
|
{
|
|
RenderCommanderUI();
|
|
}
|
|
else
|
|
{
|
|
RenderMarineUI();
|
|
}
|
|
}
|
|
else if (GetIsAlien())
|
|
{
|
|
RenderAlienUI();
|
|
}
|
|
|
|
RenderProgressBar(kProgressBarSprite);
|
|
}
|
|
|
|
if (this->GetHUDPlayMode() >= 1 && this->GetHUDPlayMode() <= 5)
|
|
{
|
|
RenderShowSpeed();
|
|
}
|
|
}
|
|
|
|
AvHSpriteEndFrame();
|
|
AvHSpriteClearViewport();
|
|
|
|
}
|
|
|
|
void AvHHud::RenderShowSpeed()
|
|
{
|
|
static bool speedMeasured = false;
|
|
if (!mSteamUIActive)
|
|
{
|
|
static int maxSpeed = 0, maxGroundSpeed = 0, maxClimb = 0, maxDive = 0;
|
|
if (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];
|
|
|
|
maxClimb = max(maxClimb, (int)pmove->velocity[2]);
|
|
maxDive = min(maxDive, (int)pmove->velocity[2]);
|
|
|
|
int speed = (int)Length(pmove->velocity);
|
|
|
|
maxSpeed = max(speed, maxSpeed);
|
|
sprintf(buffer, "Speed = %d (%d)", speed, maxSpeed/*, maxClimb, maxDive*/);
|
|
mFont.DrawString(10, 10, buffer, theR, theG, theB);
|
|
|
|
float theGroundSpeed = sqrtf(pmove->velocity[0] * pmove->velocity[0] + pmove->velocity[1] * pmove->velocity[1]);
|
|
maxGroundSpeed = max(theGroundSpeed, maxGroundSpeed);
|
|
sprintf(buffer, "Ground speed = %d (%d)", (int)theGroundSpeed, maxGroundSpeed);
|
|
mFont.DrawString(10, 12 + mFont.GetStringHeight(), buffer, theR, theG, theB);
|
|
|
|
//sprintf(buffer, "vangle0= %f vangle1= %f vangle2= %f)", pmove->angles[0], pmove->angles[1], pmove->angles[2]);
|
|
//mFont.DrawString(10, 12 + mFont.GetStringHeight() * 2, buffer, theR, theG, theB);
|
|
speedMeasured = true;
|
|
}
|
|
else if (speedMeasured == true) {
|
|
char msg[256];
|
|
sprintf(msg, "Current Speed(%d)\tCurrent Ground Speed(%d) Max Speed(%d)\t Max Ground Speed (%d)\tMax Climb (%d)\tMax Dive(%d)\n",
|
|
(int)Length(pmove->velocity), (int)sqrtf(pmove->velocity[0] * pmove->velocity[0] + pmove->velocity[1] * pmove->velocity[1]),
|
|
maxSpeed, maxGroundSpeed, maxClimb, maxDive);
|
|
ConsolePrint(msg);
|
|
maxSpeed = 0, maxGroundSpeed = 0, maxClimb = 0, maxDive = 0;
|
|
speedMeasured = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AvHHud::RenderCommonUI()
|
|
{
|
|
if (!mSteamUIActive)
|
|
{
|
|
DrawInfoLocationText();
|
|
DrawHUDStructureNotification();
|
|
|
|
this->DrawOrders();
|
|
this->DrawHelpIcons();
|
|
// : 0000971
|
|
this->DrawTeammateOrders();
|
|
// : 0000992
|
|
this->DrawDisplayOrder();
|
|
// :
|
|
|
|
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());
|
|
AVHHSPRITE theExperienceSprite = 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::RenderProgressBar(char *spriteName)
|
|
{
|
|
// Draw the progress bars
|
|
const float progressBarStayTime = 0.2f;
|
|
if (this->mProgressBarLastDrawn + progressBarStayTime > this->GetTimeOfLastUpdate())
|
|
{
|
|
AVHHSPRITE currentSprite=0;
|
|
if ( spriteName && ( strcmp(spriteName, kExperienceBarSprite) == 0 ) ) {
|
|
currentSprite=this->mExperienceBarSprite;
|
|
}
|
|
if ( spriteName && ( strcmp(spriteName, kProgressBarSprite) == 0 ) ) {
|
|
currentSprite=this->mProgressBarSprite;
|
|
}
|
|
if (currentSprite)
|
|
{
|
|
const float kNormalizedWidth = .1f;
|
|
const float kNormalizedYInset = .89f;
|
|
const float kNormalizedHeight = .025f;
|
|
|
|
// 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(currentSprite, this->mProgressBarDrawframe + 1, kXStart, kYStart, kXStart + kNormalizedWidth*ScreenWidth(), kYStart + kNormalizedHeight*ScreenHeight(), 0, 0, 1, 1);
|
|
|
|
// Draw overlay showing progress
|
|
float theProgress = this->mProgressBarStatus;
|
|
if((theProgress >= 0.0f) && (theProgress <= 1.0f))
|
|
{
|
|
AvHSpriteDraw(currentSprite, this->mProgressBarDrawframe, kXStart, kYStart, kXStart + theProgress*kNormalizedWidth*ScreenWidth(), kYStart + kNormalizedHeight*ScreenHeight(), 0, 0, theProgress, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AvHHud::RenderMiniMap(int inX, int inY, int inWidth, int inHeight)
|
|
{
|
|
|
|
AvHOverviewMap& theOverviewMap = gHUD.GetOverviewMap();
|
|
|
|
float hudMinimap=CVAR_GET_FLOAT(kvHudMapZoom);
|
|
hudMinimap=min(3, max(1, hudMinimap));
|
|
|
|
float zoomScale=(3.0f-hudMinimap);
|
|
|
|
AvHOverviewMap::DrawInfo theDrawInfo;
|
|
|
|
theDrawInfo.mX = inX;
|
|
theDrawInfo.mY = inY;
|
|
theDrawInfo.mWidth = inWidth;
|
|
theDrawInfo.mHeight = inHeight;
|
|
theDrawInfo.mFullScreen = false;
|
|
|
|
float worldViewWidth = 800 + 400.0f*zoomScale;
|
|
|
|
theDrawInfo.mZoomScale = 1-(0.25f * zoomScale );
|
|
|
|
|
|
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);
|
|
int hudMinimap=CVAR_GET_FLOAT(kvHudMapZoom);
|
|
for ( int i=0; i<3; i++ ) {
|
|
float width=theWidth/3.0f;
|
|
int frame=i;
|
|
if ( hudMinimap == 0 && i == 2 ) frame=i+1;
|
|
|
|
AvHSpriteDraw(mMarineTopSprite, frame, mViewport[2] - width*(3-i) + mViewport[0],
|
|
mViewport[1], mViewport[2] - width*(2-i) + mViewport[0], mViewport[1] + theHeight, 0, 0, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
// Draw the minimap.
|
|
if ( hudMinimap > 0 ) {
|
|
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);
|
|
AvHSpriteDraw(mMarineUpgradesSprite, 0, x1, y1, x2, y2, theStartU, theStartV, theEndU, theEndV);
|
|
|
|
}
|
|
}
|
|
|
|
bool frames[3] = { false, false, false};
|
|
if ( this->mHasGrenades ) frames[0]=true;
|
|
if ( this->mHasMines ) frames[1]=true;
|
|
if ( this->mHasWelder ) frames[2]=true;
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
{
|
|
int theFrame=i+9;
|
|
if ( frames[i] == true ) {
|
|
const int kIconWidth = .05*ScreenWidth();
|
|
const int kIconHeight = .05*ScreenHeight();
|
|
const int kBaseX = ScreenWidth() - .05*ScreenWidth();
|
|
const int kBaseY = .75*ScreenHeight();
|
|
|
|
float theStartU = (theFrame % 4)*.25f;
|
|
float theStartV = (theFrame / 4)*.333f;
|
|
float theEndU = theStartU + .25f;
|
|
float theEndV = theStartV + .333f;
|
|
|
|
float x1 = kBaseX;
|
|
float y1 = kBaseY - (i+1)*kIconHeight;
|
|
float x2 = x1 + kIconWidth;
|
|
float y2 = y1 + kIconHeight;
|
|
|
|
AvHSpriteSetRenderMode(kRenderTransAdd);
|
|
AvHSpriteEnableClippingRect(false);
|
|
AvHSpriteSetColor(1, 1, 1);
|
|
AvHSpriteDraw(mMarineUpgradesSprite, theFrame, 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;
|
|
AVHHSPRITE 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;
|
|
AVHHSPRITE 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));
|
|
|
|
AVHHSPRITE theSprite = this->mBuildCircleSprite;
|
|
// : 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);
|
|
}
|
|
// :
|
|
RenderStructureRange(thePosition, theMinMarineBuildDistance + theMaxRadius2, theSprite, kRenderTransAdd, 0, 1, 0, 0, 0.3f);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void AvHHud::RenderStructureRange(vec3_t inOrigin, int inRadius, AVHHSPRITE 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();
|
|
|
|
// : 0000989
|
|
// moved resource label a bit down
|
|
//int theResourceLabelX = mViewport[0] + kTextInset*ScreenWidth();
|
|
//int theResourceLabelY = theY - + .05f * ScreenHeight();
|
|
int theResourceLabelX = 10;
|
|
int theResourceLabelY = .68f * 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);
|
|
|
|
}
|
|
|
|
if (mAlienUICloakSprite )
|
|
{
|
|
cl_entity_s* theLocalPlayer = GetVisiblePlayer();
|
|
if(theLocalPlayer ) {
|
|
theX = mViewport[2] - theWidth + mViewport[0];
|
|
|
|
int amount=0;
|
|
int range=255-kAlienSelfCloakingBaseOpacity;
|
|
if ( theLocalPlayer->curstate.renderamt > 0 ) {
|
|
amount=theLocalPlayer->curstate.renderamt-kAlienSelfCloakingBaseOpacity;
|
|
amount=max(0, min(range, amount));
|
|
}
|
|
float theFactor = 1;
|
|
if ( theLocalPlayer->curstate.rendermode == kRenderTransTexture )
|
|
theFactor=(float)amount/(float)range;
|
|
|
|
|
|
AvHSpriteSetColor(1,1,1);
|
|
AvHSpriteSetRenderMode(kRenderTransTexture);
|
|
|
|
AvHSpriteDraw(mAlienUICloakSprite, 0, theX, theY, theX + theWidth, theY + theHeight * theFactor, 0, 0, 1, theFactor);
|
|
AvHSpriteDraw(mAlienUICloakSprite, 1, theX, theY + theHeight * theFactor, theX + theWidth, theY + theHeight, 0, theFactor, 1, 1);
|
|
// }
|
|
// else {
|
|
// int a=0;
|
|
// }
|
|
}
|
|
}
|
|
|
|
// 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.04;
|
|
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 = theLevelOfUpgrade; theLevel > 0; 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 numSprites=1;
|
|
switch ( theCategory ) {
|
|
case ALIEN_UPGRADE_CATEGORY_DEFENSE:
|
|
numSprites=this->mNumDefense;
|
|
break;
|
|
case ALIEN_UPGRADE_CATEGORY_SENSORY:
|
|
numSprites=this->mNumSensory;
|
|
break;
|
|
case ALIEN_UPGRADE_CATEGORY_MOVEMENT:
|
|
numSprites=this->mNumMovement;
|
|
break;
|
|
}
|
|
for ( int j = numSprites; j > 0; j-- ) {
|
|
const float kOffset = .01f;
|
|
int theFrame = theCategory-1;
|
|
|
|
float x1 = theX - j*(kOffset*ScreenWidth());
|
|
float y1 = theY - j*(kOffset*ScreenHeight());
|
|
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;
|
|
int theBlip = 0;
|
|
float theDotProductOfClosestBlip = -1;
|
|
|
|
// Get view vector
|
|
Vector theViewVector;
|
|
vec3_t theForward, theRight, theUp;
|
|
AngleVectors(v_angles, theForward, theRight, theUp);
|
|
VectorNormalize(theForward);
|
|
|
|
for( 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 != "") && (CVAR_GET_FLOAT(kvLabelHivesight) == 1))
|
|
{
|
|
// Find alpha for the blip-text based on position on the screen
|
|
float screenWidth = ScreenWidth();
|
|
float screenHeight = ScreenHeight();
|
|
float xdiff = fabs(theScreenPos[0] - screenWidth/2);
|
|
float ydiff = fabs(theScreenPos[1] - screenHeight/2);
|
|
float quadrance = xdiff * xdiff + ydiff * ydiff;
|
|
float alpha = max(0.0f, 0.9f - quadrance / (screenHeight * screenHeight));
|
|
alpha *= alpha * alpha * alpha;
|
|
|
|
// "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, false, alpha);
|
|
|
|
char theLocationNameCStr[512];
|
|
strcpy(theLocationNameCStr, theLocationName.c_str());
|
|
this->DrawTranslatedString(theScreenPos[0], theScreenPos[1] + .022f*ScreenHeight(), theLocationNameCStr, true, true, true, alpha);
|
|
}
|
|
}
|
|
|
|
//}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
// If building, draw time until completion.
|
|
else if (theIter->mStatus > 0 && theIter->mStatus < 6)
|
|
{
|
|
const int totalBuildTime = BALANCE_VAR(kHiveBuildTime);
|
|
if (theIter->mBuildTime > 0 && theIter->mBuildTime < totalBuildTime)
|
|
{
|
|
int timeLeft = theIter->mBuildTime;
|
|
int theMinutesLeft = timeLeft / 60;
|
|
int theSecondsLeft = timeLeft % 60;
|
|
|
|
if (theMinutesLeft)
|
|
theTranslatedLocationName = MakeStringFromInt(theMinutesLeft) + "m " + MakeStringFromInt(theSecondsLeft) + "s - " + theTranslatedLocationName;
|
|
else
|
|
theTranslatedLocationName = MakeStringFromInt(theSecondsLeft) + "s - " + theTranslatedLocationName;
|
|
}
|
|
}
|
|
|
|
this->DrawHudStringReverse(mViewport[0] + mViewport[2] - 5, theScreenPosY, ScreenWidth(), (char*)theTranslatedLocationName.c_str(), theR, theG, theB);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void AvHHud::DrawWarpedOverlaySprite(AVHHSPRITE 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::InitHUDData( void )
|
|
{
|
|
this->ResetGame(true);
|
|
}
|
|
|
|
void AvHHud::VidInit(void)
|
|
{
|
|
UIHud::VidInit();
|
|
|
|
mOverviewMap.VidInit();
|
|
|
|
int theScreenWidth = ScreenWidth();
|
|
string theSpriteName;
|
|
|
|
// theSpriteName = UINameToSprite(kEggSprite, theScreenWidth);
|
|
// this->mAlienUIEggSprite = SPR_Load(theSpriteName.c_str());
|
|
|
|
// theSpriteName = UINameToSprite(kHiveSprite, theScreenWidth);
|
|
// this->mAlienUIHiveSprite = 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] = SPR_Load(theSpriteName.c_str());
|
|
// }
|
|
|
|
if (CVAR_GET_FLOAT("hud_style") == 2.0f)
|
|
{
|
|
this->mAlienUIUpgrades = SPR_Load(kAlienUpgradeSpriteNL);
|
|
this->mAlienUIEnergySprite = SPR_Load(kAlienEnergySpriteNL);
|
|
this->mAlienUICloakSprite = SPR_Load(kAlienCloakSpriteNL);
|
|
this->mBackgroundSprite = SPR_Load(kTopDownBGSpriteNL);
|
|
this->mTopDownTopSprite = SPR_Load(kTopDownTopHUDSpriteNL);
|
|
this->mTopDownBottomSprite = SPR_Load(kTopDownBottomHUDSpriteNL);
|
|
this->mMarineTopSprite = SPR_Load(kMarineTopHUDSpriteNL);
|
|
this->mLogoutSprite = SPR_Load(kLogoutSpriteNL);
|
|
this->mCommandButtonSprite = SPR_Load(kCommandButtonSpriteNL);
|
|
this->mCommandStatusSprite = SPR_Load(kCommandStatusSpriteNL);
|
|
this->mSelectAllSprite = SPR_Load(kSelectAllSpriteNL);
|
|
this->mOrderSprite = SPR_Load(kOrdersSpriteNL);
|
|
this->mHiveInfoSprite = SPR_Load(kHiveInfoSpriteNL);
|
|
this->mHiveHealthSprite = SPR_Load(kHiveHealthSpriteNL);
|
|
this->mMarineOrderIndicator = SPR_Load(kMarineOrderSpriteNL);
|
|
this->mMarineUpgradesSprite = SPR_Load(kMarineUpgradesSpriteNL);
|
|
}
|
|
else if (CVAR_GET_FLOAT("hud_style") == 1.0f)
|
|
{
|
|
char theBaseName[128];
|
|
sprintf(theBaseName, "%s", kAlienUpgradeSprite);
|
|
theSpriteName = UINameToSprite(theBaseName, theScreenWidth);
|
|
this->mAlienUIUpgrades = SPR_Load(theSpriteName.c_str());
|
|
|
|
// Load alien energy sprite
|
|
theSpriteName = UINameToSprite(kAlienEnergySprite, theScreenWidth);
|
|
this->mAlienUIEnergySprite = SPR_Load(theSpriteName.c_str());
|
|
theSpriteName = UINameToSprite(kAlienCloakSprite, theScreenWidth);
|
|
|
|
this->mAlienUICloakSprite = SPR_Load(theSpriteName.c_str());
|
|
this->mBackgroundSprite = SPR_Load(kTopDownBGSprite);
|
|
this->mTopDownTopSprite = SPR_Load(kTopDownTopHUDSpriteMin);
|
|
this->mTopDownBottomSprite = SPR_Load(kTopDownBottomHUDSpriteMin);
|
|
this->mMarineTopSprite = SPR_Load(kMarineTopHUDSpriteMin);
|
|
this->mLogoutSprite = SPR_Load(kLogoutSprite);
|
|
this->mCommandButtonSprite = SPR_Load(kCommandButtonSprite);
|
|
this->mCommandStatusSprite = SPR_Load(kCommandStatusSpriteMin);
|
|
this->mSelectAllSprite = SPR_Load(kSelectAllSpriteMin);
|
|
// Load order sprite
|
|
theSpriteName = UINameToSprite(kOrdersSprite, theScreenWidth);
|
|
this->mOrderSprite = SPR_Load(theSpriteName.c_str());
|
|
this->mHiveInfoSprite = SPR_Load(kHiveInfoSprite);
|
|
this->mHiveHealthSprite = SPR_Load(kHiveHealthSprite);
|
|
this->mMarineOrderIndicator = SPR_Load(kMarineOrderSprite);
|
|
this->mMarineUpgradesSprite = SPR_Load(kMarineUpgradesSprite);
|
|
}
|
|
else
|
|
{
|
|
char theBaseName[128];
|
|
sprintf(theBaseName, "%s", kAlienUpgradeSprite);
|
|
theSpriteName = UINameToSprite(theBaseName, theScreenWidth);
|
|
this->mAlienUIUpgrades = SPR_Load(theSpriteName.c_str());
|
|
|
|
// Load alien energy sprite
|
|
theSpriteName = UINameToSprite(kAlienEnergySprite, theScreenWidth);
|
|
this->mAlienUIEnergySprite = SPR_Load(theSpriteName.c_str());
|
|
theSpriteName = UINameToSprite(kAlienCloakSprite, theScreenWidth);
|
|
this->mAlienUICloakSprite = SPR_Load(theSpriteName.c_str());
|
|
|
|
// Load background for topdown mode
|
|
this->mBackgroundSprite = SPR_Load(kTopDownBGSprite);
|
|
|
|
// Load HUD
|
|
this->mTopDownTopSprite = SPR_Load(kTopDownTopHUDSprite);
|
|
this->mTopDownBottomSprite = SPR_Load(kTopDownBottomHUDSprite);
|
|
this->mMarineTopSprite = SPR_Load(kMarineTopHUDSprite);
|
|
|
|
this->mLogoutSprite = SPR_Load(kLogoutSprite);
|
|
this->mCommandButtonSprite = SPR_Load(kCommandButtonSprite);
|
|
this->mCommandStatusSprite = SPR_Load(kCommandStatusSprite);
|
|
this->mSelectAllSprite = SPR_Load(kSelectAllSprite);
|
|
|
|
// Load order sprite
|
|
theSpriteName = UINameToSprite(kOrdersSprite, theScreenWidth);
|
|
this->mOrderSprite = SPR_Load(theSpriteName.c_str());
|
|
this->mHiveInfoSprite = SPR_Load(kHiveInfoSprite);
|
|
this->mHiveHealthSprite = SPR_Load(kHiveHealthSprite);
|
|
|
|
this->mMarineOrderIndicator = SPR_Load(kMarineOrderSprite);
|
|
this->mMarineUpgradesSprite = SPR_Load(kMarineUpgradesSprite);
|
|
}
|
|
|
|
char theBaseName[128];
|
|
sprintf(theBaseName, "%s", kAlienUpgradeCategory);
|
|
theSpriteName = UINameToSprite(theBaseName, theScreenWidth);
|
|
this->mAlienUIUpgradeCategories = SPR_Load(theSpriteName.c_str());
|
|
|
|
// Load jetpack sprite
|
|
theSpriteName = UINameToSprite(kJetpackSprite, theScreenWidth);
|
|
this->mMarineUIJetpackSprite = SPR_Load(theSpriteName.c_str());
|
|
|
|
//this->mTopDownBottomSprite = SPR_Load("sprites/distorttest.spr");
|
|
//this->mTopDownBottomSprite = SPR_Load("sprites/ns.spr");
|
|
//this->mTopDownBottomSprite = SPR_Load("sprites/distorttest.spr");
|
|
|
|
// Load overlays
|
|
this->mMembraneSprite = SPR_Load(kMembraneSprite);
|
|
this->mDigestingSprite = SPR_Load(kDigestingSprite);
|
|
|
|
// Load cursor sprite
|
|
this->mMarineCursor = SPR_Load(kCursorsSprite);
|
|
this->mAlienCursor = SPR_Load(kAlienCursorSprite);
|
|
//this->mMappingTechSprite = SPR_Load("sprites/ns.spr");
|
|
|
|
this->mAlienBuildSprite = SPR_Load(kAlienBuildSprite);
|
|
this->mMarineBuildSprite = SPR_Load(kMarineBuildSprite);
|
|
|
|
this->mAlienHealthSprite = SPR_Load(kAlienHealthSprite);
|
|
this->mMarineHealthSprite = SPR_Load(kMarineHealthSprite);
|
|
|
|
this->mBuildCircleSprite = SPR_Load(kBuildCircleSprite);
|
|
//this->mSiegeTurretSprite = SPR_Load(kSiegeTurretSprite);
|
|
|
|
this->mActionButtonSprites.clear();
|
|
//this->mHelpSprites.clear();
|
|
|
|
string theIconName = string(kHelpIconPrefix) + ".spr";
|
|
this->mHelpSprite = SPR_Load(theIconName.c_str());
|
|
|
|
// : 0000971
|
|
this->mTeammateOrderSprite = SPR_Load(kTeammateOrderSprite);
|
|
// :
|
|
|
|
this->mExperienceBarSprite = SPR_Load(kExperienceBarSprite);
|
|
this->mProgressBarSprite = SPR_Load(kProgressBarSprite);
|
|
|
|
this->mEnemyBlips.VidInit();
|
|
this->mFriendlyBlips.VidInit();
|
|
}
|