Skip to content
This repository was archived by the owner on May 25, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 156 additions & 42 deletions mp/src/game/client/neo/ui/neo_hud_ammo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
#include "ienginevgui.h"

#include "neo_hud_elements.h"
#include "inttostr.h"

#include "ammodef.h"

#include "weapon_ghost.h"
#include "weapon_grenade.h"
#include "weapon_neobasecombatweapon.h"
#include "weapon_smokegrenade.h"
#include "weapon_supa7.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

Expand All @@ -26,10 +33,10 @@ using vgui::surface;

ConVar neo_cl_hud_ammo_enabled("neo_cl_hud_ammo_enabled", "1", FCVAR_USERINFO,
"Whether the HUD ammo is enabled or not.", true, 0, true, 1);
ConVar neo_cl_hud_ammo_pos_x("neo_cl_hud_ammo_pos_x", "15", FCVAR_USERINFO,
"HUD ammo X offset divisor.", true, 1, false, 100);
ConVar neo_cl_hud_ammo_pos_y("neo_cl_hud_ammo_pos_y", "20", FCVAR_USERINFO,
"HUD ammo Y offset divisor.", true, 1, false, 100);
ConVar neo_cl_hud_ammo_pos_x("neo_cl_hud_ammo_pos_x", "5", FCVAR_USERINFO,
"HUD ammo X offset divisor.", true, 1, false, 0);
ConVar neo_cl_hud_ammo_pos_y("neo_cl_hud_ammo_pos_y", "5", FCVAR_USERINFO,
"HUD ammo Y offset divisor.", true, 1, false, 0);

ConVar neo_cl_hud_debug_ammo_color_r("neo_cl_hud_debug_ammo_color_r", "190", FCVAR_USERINFO | FCVAR_CHEAT,
"Red color value of the ammo, in range 0 - 255.", true, 0.0f, true, 255.0f);
Expand Down Expand Up @@ -68,8 +75,9 @@ CNEOHud_Ammo::CNEOHud_Ammo(const char* pElementName, vgui::Panel* parent)
Error("CNEOHud_Ammo: Failed to load neoscheme\n");
}

m_hTextFont = scheme->GetFont("NHudOCRSmall");
m_hSmallTextFont = scheme->GetFont("NHudOCRSmall");
m_hBulletFont = scheme->GetFont("NHudBullets");
m_hTextFont = scheme->GetFont("NHudOCR");

SetVisible(neo_cl_hud_ammo_enabled.GetBool());

Expand Down Expand Up @@ -99,6 +107,12 @@ void CNEOHud_Ammo::ApplySchemeSettings(vgui::IScheme* pScheme)
SetBounds(0, 0, m_resX, m_resY);

SetRoundedCorners(PANEL_ROUND_CORNER_ALL); // FIXME

wchar_t sampleText[1] = { 'a' };
surface()->GetTextSize(m_hSmallTextFont, sampleText, m_smallFontWidth, m_smallFontHeight);
sampleText[0] = { 'h' };
surface()->GetTextSize(m_hBulletFont, sampleText, m_bulletFontWidth, m_bulletFontHeight);
m_fontWidth = surface()->GetCharacterWidth(m_hTextFont, '4'); //Widest character
}

void CNEOHud_Ammo::DrawAmmo() const
Expand All @@ -112,6 +126,7 @@ void CNEOHud_Ammo::DrawAmmo() const
}

const Color textColor = COLOR_WHITE;
auto textColorTransparent = Color(textColor.r(), textColor.g(), textColor.b(), 127);

const size_t maxWepnameLen = 64;
char wepName[maxWepnameLen]{ '\0' };
Expand All @@ -125,57 +140,156 @@ void CNEOHud_Ammo::DrawAmmo() const
}
g_pVGuiLocalize->ConvertANSIToUnicode(wepName, unicodeWepName, sizeof(unicodeWepName));

int fontWidth, fontHeight;
surface()->GetTextSize(m_hTextFont, unicodeWepName, fontWidth, fontHeight);

const int margin = GetMargin(); //Get this from scheme?

// These are the constant res based scalings of the NT ammo/health box dimensions.
const int xpos = m_resX - (m_resX * 0.2375);
const int ypos = m_resY - (m_resY * (0.1 / 1.5));

const int margin = neo_cl_hud_ammo_enabled.GetInt();
DrawNeoHudRoundedBox(xpos - margin, ypos - margin, m_resX - margin, m_resY - margin);

surface()->DrawSetTextFont(m_hTextFont);
surface()->DrawSetTextColor(textColor);
surface()->DrawSetTextPos(m_resX - fontWidth * 1.5 - margin, ypos + fontHeight * 0.5 - margin);
const int xPos1 = m_resX - neo_cl_hud_ammo_pos_x.GetInt();
const int yPos1 = m_resY - neo_cl_hud_ammo_pos_y.GetInt();
const int xPos0 = xPos1 - ((m_resX * 0.2375) + (margin * 2));
const int yPos0 = yPos1 - (((m_bulletFontHeight * 0.8) + m_smallFontHeight + margin * 2) + (margin * 2));


DrawNeoHudRoundedBox(xPos0, yPos0, xPos1, yPos1);

surface()->DrawSetTextFont(m_hSmallTextFont);
surface()->DrawSetTextColor(textColorTransparent);
int weaponNamePixelWidth, weaponNamePixelHeight;
surface()->GetTextSize(m_hSmallTextFont, unicodeWepName, weaponNamePixelWidth, weaponNamePixelHeight);
surface()->DrawSetTextPos(xPos1 - ((margin * 2) + weaponNamePixelWidth + m_fontWidth / 2), yPos0 + (margin / 2));
surface()->DrawPrintText(unicodeWepName, textLen);

if(dynamic_cast<C_WeaponGhost*> (activeWep))
{
return;
}

const int maxClip = activeWep->GetMaxClip1();
if (maxClip != 0)
if (maxClip != 0 && !activeWep->IsMeleeWeapon())
{
const auto ammo = GetAmmoDef()->GetAmmoOfIndex(activeWep->GetPrimaryAmmoType());
const int ammoCount = activeWep->GetOwner()->GetAmmoCount(ammo->pName);
const int numClips = abs(ammoCount / activeWep->GetMaxClip1()); // abs because grenades return negative values (???)
const int numClips = ceil(abs((float)ammoCount / activeWep->GetMaxClip1())); // abs because grenades return negative values (???) // casting division to float in case we have a half-empty mag, rounding up to show the half mag as one more mag
const auto isSupa = dynamic_cast<CWeaponSupa7*>(activeWep);

const int maxLen = 5;
char clipsText[maxLen]{ '\0' };
if(isSupa)
{
const auto secondaryAmmo = GetAmmoDef()->GetAmmoOfIndex(activeWep->GetSecondaryAmmoType());
snprintf(clipsText, 10, "%d+%d", ammoCount, activeWep->GetOwner()->GetAmmoCount(secondaryAmmo->pName));
} else
{
snprintf(clipsText, 10, "%d", numClips);
}
textLen = V_strlen(clipsText);
wchar_t unicodeClipsText[maxLen]{ L'\0' };
g_pVGuiLocalize->ConvertANSIToUnicode(clipsText, unicodeClipsText, sizeof(unicodeClipsText));

int clipsTextWidth, clipsTextHeight;
surface()->GetTextSize(m_hTextFont, unicodeClipsText, clipsTextWidth, clipsTextHeight);
surface()->DrawSetTextFont(m_hTextFont);
surface()->DrawSetTextPos(xPos1 - (clipsTextWidth + margin), yPos0 + (margin * 2) + m_smallFontHeight);
surface()->DrawPrintText(unicodeClipsText, textLen);

const auto neoWep = dynamic_cast<C_NEOBaseCombatWeapon*> (activeWep);

// Render amount of clips remaining. Sort of an approximation, should revisit once unfinished mag "reload dumping" is implemented.
if (numClips != 0)
char* ammoChar = nullptr;
int fireModeWidth = 0, fireModeHeight = 0;
int magSizeMax = 0;
int magSizeCurrent = 0;

if (activeWep->UsesClipsForAmmo1())
{
char fireModeText[2]{ L'\0' };

ammoChar = const_cast<char*>(activeWep->GetWpnData().szBulletCharacter);
magSizeMax = activeWep->GetMaxClip1();
magSizeCurrent = activeWep->Clip1();

if(neoWep)
{
if(neoWep->IsAutomatic())
fireModeText[0] = 'j';
else if(isSupa)
if(isSupa->SlugLoaded())
fireModeText[0] = 'h';
else
fireModeText[0] = 'l';
else
fireModeText[0] = 'h';


wchar_t unicodeFireModeText[2]{ L'\0' };
g_pVGuiLocalize->ConvertANSIToUnicode(fireModeText, unicodeFireModeText, sizeof(unicodeFireModeText));

surface()->DrawSetTextFont(m_hBulletFont);
surface()->DrawSetTextPos(xPos0 + margin, yPos0 + ((((yPos1 - margin) - yPos0) / 2) - ((m_bulletFontHeight * 0.8) / 2)));
surface()->DrawPrintText(unicodeFireModeText, V_strlen(fireModeText));

surface()->GetTextSize(m_hBulletFont, unicodeFireModeText, fireModeWidth, fireModeHeight);
}
} else
{
if(dynamic_cast<CWeaponSmokeGrenade*> (activeWep))
{
ammoChar = new char[2] { 'f', '\0' };
magSizeMax = magSizeCurrent = ammoCount;
} else if(dynamic_cast<CWeaponGrenade*> (activeWep))
{
ammoChar = new char[2] { 'g', '\0' };
magSizeMax = magSizeCurrent = ammoCount;
}
}

auto maxSpaceAvaliableForBullets = (xPos1 - (margin + max(clipsTextWidth, m_fontWidth))) - (xPos0 + fireModeWidth + (margin * 2));
auto bulletWidth = surface()->GetCharacterWidth(m_hBulletFont, *ammoChar);
auto plusWidth = surface()->GetCharacterWidth(m_hBulletFont, '+');
auto maxBulletsWeCanDisplay = maxSpaceAvaliableForBullets / bulletWidth;
auto maxBulletsWeCanDisplayWithPlus = (maxSpaceAvaliableForBullets - plusWidth) / bulletWidth;
auto bulletsOverflowing = maxBulletsWeCanDisplay < magSizeMax;

if(bulletsOverflowing)
{
const int maxLen = 4; // support a max of '999' clips, plus '\0'
char clipsText[maxLen]{ '\0' };
itoa(numClips, clipsText, 10);
textLen = V_strlen(clipsText);
wchar_t unicodeClipsText[maxLen]{ L'\0' };
g_pVGuiLocalize->ConvertANSIToUnicode(clipsText, unicodeClipsText, sizeof(unicodeClipsText));

surface()->DrawSetTextPos(m_resX - fontWidth * 1.5 - margin, ypos + fontHeight * 2.5 - margin);
surface()->DrawPrintText(unicodeClipsText, textLen);
magSizeMax = maxBulletsWeCanDisplayWithPlus + 1;
}

// Render the bullet icons representing the amount of bullets in current clip.
if (ammoCount != 0 && activeWep->UsesClipsForAmmo1())
magSizeMax = min(magSizeMax, 64);
char bullets[64]{ '\0' };
for(int i = 0; i < magSizeMax; i++)
{
const int maxBulletsInClip = 63 + 1;
char bullets[maxBulletsInClip]{ '\0' };
for (int i = 0, numBulletsInCurClip = activeWep->Clip1(); i < maxBulletsInClip && numBulletsInCurClip != 0; ++i) {
V_strcat_safe(bullets, "a");
--numBulletsInCurClip;
bullets[i] = *ammoChar;
}

int magAmountToDrawFilled = magSizeCurrent;

if(bulletsOverflowing)
{
bullets[magSizeMax - 1] = '+';

if(maxClip == magSizeCurrent)
{
magAmountToDrawFilled = magSizeMax;
} else if(magSizeMax - 1 < magSizeCurrent)
{
magAmountToDrawFilled = magSizeMax - 1;
} else
{
magAmountToDrawFilled = magSizeCurrent;
}
wchar_t unicodeBullets[maxBulletsInClip]{ L'\0' };
g_pVGuiLocalize->ConvertANSIToUnicode(bullets, unicodeBullets, sizeof(unicodeBullets));
}

wchar_t unicodeBullets[64];
g_pVGuiLocalize->ConvertANSIToUnicode(bullets, unicodeBullets, sizeof(unicodeBullets));

surface()->DrawSetTextFont(m_hBulletFont);
surface()->DrawSetTextPos(xPos0 + fireModeWidth + (margin * 2), (yPos0 + margin + m_smallFontHeight) - (m_bulletFontHeight * 0.2));
surface()->DrawPrintText(unicodeBullets, magAmountToDrawFilled);

surface()->DrawSetTextFont(m_hBulletFont);
surface()->DrawSetTextPos(xpos + 10 - margin, ypos + 10 - margin); // TODO: resolution scaling for the offsets here
surface()->DrawPrintText(unicodeBullets, activeWep->Clip1());
if(maxClip > 0)
{
surface()->DrawSetColor(textColor);
surface()->DrawSetTextPos(xPos0 + fireModeWidth + (margin * 2), (yPos0 + margin + m_smallFontHeight) - (m_bulletFontHeight * 0.2));
surface()->DrawPrintText(unicodeBullets, magSizeMax);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions mp/src/game/client/neo/ui/neo_hud_ammo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ class CNEOHud_Ammo : public CNEOHud_ChildElement, public CHudElement, public vgu
void DrawAmmo() const;

private:
vgui::HFont m_hSmallTextFont;
vgui::HFont m_hTextFont;
vgui::HFont m_hBulletFont;

int m_resX, m_resY;
int m_smallFontWidth, m_smallFontHeight;
int m_fontWidth;
int m_bulletFontWidth, m_bulletFontHeight;

private:
CNEOHud_Ammo(const CNEOHud_Ammo& other);
Expand Down
8 changes: 7 additions & 1 deletion mp/src/game/client/neo/ui/neo_hud_childelement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

using vgui::surface;

#define NEO_HUDBOX_COLOR Color(116, 116, 116, 200)
#define NEO_HUDBOX_COLOR Color(116, 116, 116, 178)
#define NEO_HUDBOX_CORNER_SCALE 1.0

// NEO TODO (Rain): this should be expanded into two margin_width/height cvars, so players can tweak their HUD position if they wish to.
Expand Down Expand Up @@ -75,3 +75,9 @@ void CNEOHud_ChildElement::DrawNeoHudRoundedBox(const int x0, const int y0, cons
surface()->DrawFilledRect(x0, y0h, x0w, y1h);
surface()->DrawFilledRect(x1w, y0h, x1, y1h);
}

int CNEOHud_ChildElement::GetMargin()
{
return neo_cl_hud_margin.GetInt();
}

2 changes: 2 additions & 0 deletions mp/src/game/client/neo/ui/neo_hud_childelement.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class CNEOHud_ChildElement

CNeoHudElements* GetRootNeoHud() const { return m_pNeoHud; }

static int GetMargin();

private:
float GetUpdateFrequency() const { return GetUpdateFrequencyConVar()->GetFloat(); }

Expand Down
12 changes: 12 additions & 0 deletions mp/src/game/shared/neo/weapons/weapon_supa7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,15 @@ void CWeaponSupa7::AddViewKick(void)
punch.Init(SharedRandomFloat("supapax", -2, -1), SharedRandomFloat("supapay", -1, 1), 0);
pPlayer->ViewPunch(punch);
}

bool C_WeaponSupa7::SlugLoaded() const
{
return m_bSlugLoaded;
}


bool C_WeaponSupa7::SlugLoaded() const
{
return m_bSlugLoaded;
}

1 change: 1 addition & 0 deletions mp/src/game/shared/neo/weapons/weapon_supa7.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class CWeaponSupa7 : public CNEOBaseCombatWeapon
bool StartReloadSlug(void);
bool Reload(void);
bool ReloadSlug(void);
bool SlugLoaded(void) const;

void FillClip(void);
void FillClipSlug(void);
Expand Down