From 9437a182698320d761cda63f6e767a9bac975128 Mon Sep 17 00:00:00 2001 From: FileEX Date: Fri, 1 Nov 2024 23:48:05 +0100 Subject: [PATCH 1/5] Hud customization --- Client/game_sa/CGameSA.cpp | 1 + Client/game_sa/CGameSA.h | 1 + Client/game_sa/CHudSA.cpp | 357 +++++++++++++++++- Client/game_sa/CHudSA.h | 127 ++++++- Client/game_sa/CPlayerInfoSA.h | 2 + .../logic/lua/CLuaFunctionParseHelpers.cpp | 9 + .../logic/lua/CLuaFunctionParseHelpers.h | 1 + .../logic/luadefs/CLuaPlayerDefs.cpp | 169 +++++++++ .../deathmatch/logic/luadefs/CLuaPlayerDefs.h | 2 + Client/sdk/game/CGame.h | 1 + Client/sdk/game/CHud.h | 20 + Client/sdk/game/CPlayerInfo.h | 2 + Shared/sdk/SharedUtil.Defines.h | 2 + Shared/sdk/SharedUtil.Misc.h | 14 + 14 files changed, 702 insertions(+), 6 deletions(-) diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 07ac611c09..270df5009c 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -242,6 +242,7 @@ CGameSA::CGameSA() D3DResourceSystemSA::StaticSetHooks(); CVehicleSA::StaticSetHooks(); CCheckpointSA::StaticSetHooks(); + CHudSA::StaticSetHooks(); } CGameSA::~CGameSA() diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index cf4788d953..bb2e06896a 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -190,6 +190,7 @@ class CGameSA : public CGame int32_t GetCountOfAllFileIDs() { return (*(char**)(0x5B8AFA + 2) - *(char**)(0x5B8B08 + 6)) / sizeof(CStreamingInfo); } DWORD GetSystemTime() { return *(DWORD*)0xB7CB84; } // CTimer::m_snTimeInMilliseconds + int GetSystemFrameCounter() { return *(int*)0xB7CB4C; } // CTimer::m_FrameCounter bool IsAtMenu() { return *(unsigned long*)0xBA677B != 0; } // FrontEndMenuManager + 0x33 diff --git a/Client/game_sa/CHudSA.cpp b/Client/game_sa/CHudSA.cpp index 6b9c2ff770..630438bab2 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -21,6 +21,16 @@ extern CGameSA* pGame; char szVehicleName[50] = {'\0'}; char szZoneName[50] = {'\0'}; +static ComponentProperties componentProperties; + +RsGlobal* CHudSA::rsGlobal = reinterpret_cast(VAR_RSGlobal); +std::int16_t* CHudSA::itemToFlash = reinterpret_cast(VAR_ItemToFlash); + +float CHudSA::calcStreetchX = 0.0f; +float CHudSA::calcStreetchY = 0.0f; + +constexpr RwColor COLOR_BLACK = RwColor{0, 0, 0, 0}; + CHudSA::CHudSA() { InitComponentList(); @@ -33,6 +43,8 @@ CHudSA::CHudSA() m_pfAspectRatioMultiplicator = (float*)VAR_AspectRatioMult; MemPut(m_pfAspectRatioMultiplicator, 0.002232143f); + UpdateStreetchCalculations(); + // Patch xrefs to 0x863B34, because this variable seems to be shared (2 other functions without any context access to it; probably a compiler optimization) MemPut(0x58E7D4 + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x58E7EA + 2, (DWORD)&m_fSniperCrosshairScale); @@ -40,6 +52,11 @@ CHudSA::CHudSA() MemPut(0x53E41A + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x53E488 + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x53E4BF + 2, (DWORD)&m_fSniperCrosshairScale); + + // Initalize default colors + componentProperties.hpBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::RED); + componentProperties.breathBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE); + componentProperties.armorBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY); } void CHudSA::Disable(bool bDisabled) @@ -69,9 +86,9 @@ void CHudSA::InitComponentList() SHudComponent componentList[] = { {1, HUD_AMMO, 1, FUNC_DrawAmmo, 1, 0xCC, 0xC3}, {1, HUD_WEAPON, 1, FUNC_DrawWeaponIcon, 1, 0xCC, 0xC3}, - {1, HUD_HEALTH, 1, FUNC_PrintHealthForPlayer, 1, 0xCC, 0xC3}, - {1, HUD_BREATH, 1, FUNC_PrintBreathForPlayer, 1, 0xCC, 0xC3}, - {1, HUD_ARMOUR, 1, FUNC_PrintArmourForPlayer, 1, 0xCC, 0xC3}, + {1, HUD_HEALTH, 1, FUNC_RenderHealthBar, 1, 0xCC, 0xC3}, + {1, HUD_BREATH, 1, FUNC_RenderBreathBar, 1, 0xCC, 0xC3}, + {1, HUD_ARMOUR, 1, FUNC_RenderArmorBar, 1, 0xCC, 0xC3}, {1, HUD_MONEY, 1, CODE_ShowMoney, 2, 0xCCCC, 0xE990}, {1, HUD_VEHICLE_NAME, 1, FUNC_DrawVehicleName, 1, 0xCC, 0xC3}, {1, HUD_AREA_NAME, 1, FUNC_DrawAreaName, 1, 0xCC, 0xC3}, @@ -150,6 +167,27 @@ bool CHudSA::IsComponentVisible(eHudComponent component) return false; } +void CHudSA::UpdateStreetchCalculations() +{ + calcStreetchX = rsGlobal->maximumWidth * (*reinterpret_cast(VAR_AspectRatioMultX)); + calcStreetchY = rsGlobal->maximumHeight * (*m_pfAspectRatioMultiplicator); + + ComponentPlacement& hpPlacement = componentProperties.hpBar.bar.placement; + hpPlacement.height = calcStreetchY * 9.0f; + hpPlacement.width = calcStreetchX * 109.0f; + hpPlacement.setDefaultXY = false; + + ComponentPlacement& breathPlacement = componentProperties.breathBar.bar.placement; + breathPlacement.height = calcStreetchY * 9.0f; + breathPlacement.width = calcStreetchX * 62.0f; + breathPlacement.setDefaultXY = false; + + ComponentPlacement& armorPlacement = componentProperties.armorBar.bar.placement; + armorPlacement.height = calcStreetchY * 9.0f; + armorPlacement.width = calcStreetchX * 62.0f; + armorPlacement.setDefaultXY = false; +} + // // CHudSA::AdjustComponents // @@ -165,6 +203,8 @@ void CHudSA::AdjustComponents(float fAspectRatio) // Set the camera crosshair scale (same display flaw as in #7659) MemPut(m_pfCameraCrosshairScale, 192.0f * (4.0f / 3.0f) / fAspectRatio); + + UpdateStreetchCalculations(); } // @@ -176,6 +216,8 @@ void CHudSA::ResetComponentAdjustment() MemPut(m_pfAspectRatioMultiplicator, 0.002232143f); MemPut(m_pfCameraCrosshairScale, 192.0f); m_fSniperCrosshairScale = 210.0f; + + UpdateStreetchCalculations(); } bool CHudSA::IsCrosshairVisible() @@ -228,3 +270,312 @@ bool CHudSA::IsCrosshairVisible() std::uint8_t crossHairType = *reinterpret_cast(VAR_CTheScripts_bDrawCrossHair); return specialAiming || simpleAiming || crossHairType > 0; } + +RwColor CHudSA::GetHUDColour(const eHudColour& colour) +{ + switch (colour) + { + case eHudColour::RED: + return {180, 25, 29, 255}; + case eHudColour::GREEN: + return {54, 104, 44, 255}; + case eHudColour::DARK_BLUE: + return {50, 60, 127, 255}; + case eHudColour::LIGHT_BLUE: + return {172, 203, 241, 255}; + case eHudColour::LIGHT_GRAY: + return {225, 225, 225, 255}; + case eHudColour::BLACK: + return {0, 0, 0, 255}; + case eHudColour::GOLD: + return {144, 98, 16, 255}; + case eHudColour::PURPLE: + return {168, 110, 252, 255}; + case eHudColour::DARK_GRAY: + return {150, 150, 150, 255}; + case eHudColour::DARK_RED: + return {104, 15, 17, 255}; + case eHudColour::DARK_GREEN: + return {38, 71, 31, 255}; + case eHudColour::CREAM: + return {226, 192, 99, 255}; + case eHudColour::NIGHT_BLUE: + return {74, 90, 107, 255}; + case eHudColour::BLUE: + return {20, 25, 200, 255}; + case eHudColour::YELLOW: + return {255, 255, 0, 255}; + default: + return {0, 0, 0, 255}; + } +} + +HudBar& CHudSA::GetHudBarRef(const eHudComponent& component) noexcept +{ + switch (component) + { + case HUD_HEALTH: + return componentProperties.hpBar.bar; + case HUD_BREATH: + return componentProperties.breathBar.bar; + case HUD_ARMOUR: + return componentProperties.armorBar.bar; + } +} + +void CHudSA::SetComponentPlacementPosition(ComponentPlacement& placement, const CVector2D& position) +{ + placement.customX = position.fX; + placement.customY = position.fY; + placement.useCustomPosition = true; +} + +void CHudSA::SetComponentPlacementSize(ComponentPlacement& placement, const CVector2D& size) +{ + placement.customWidth = size.fX; + placement.customHeight = size.fY; + placement.useCustomSize = true; +} + +void CHudSA::SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept +{ + switch (component) + { + case HUD_BREATH: + SetComponentPlacementPosition(componentProperties.breathBar.bar.placement, position); + break; + case HUD_HEALTH: + SetComponentPlacementPosition(componentProperties.hpBar.bar.placement, position); + break; + case HUD_ARMOUR: + SetComponentPlacementPosition(componentProperties.armorBar.bar.placement, position); + break; + } +} + +void CHudSA::SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept +{ + switch (component) + { + case HUD_BREATH: + SetComponentPlacementSize(componentProperties.breathBar.bar.placement, size); + break; + case HUD_HEALTH: + SetComponentPlacementSize(componentProperties.hpBar.bar.placement, size); + break; + case HUD_ARMOUR: + SetComponentPlacementSize(componentProperties.armorBar.bar.placement, size); + break; + } +} + +void CHudSA::ResetComponent(ComponentPlacement& placement, bool resetSize) noexcept +{ + if (resetSize) + { + placement.useCustomSize = false; + placement.customHeight = 0.0f; + placement.customWidth = 0.0f; + } + else + { + placement.useCustomPosition = false; + placement.customX = 0.0f; + placement.customY = 0.0f; + } +} + +void CHudSA::ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept +{ + switch (component) + { + case HUD_ALL: + { + for (const auto& cmp : m_HudComponentMap) + { + if (cmp.first == HUD_ALL) + continue; + + ResetComponentPlacement(cmp.first, resetSize); + } + + break; + } + case HUD_HEALTH: + ResetComponent(componentProperties.hpBar.bar.placement, resetSize); + break; + case HUD_BREATH: + ResetComponent(componentProperties.breathBar.bar.placement, resetSize); + break; + case HUD_ARMOUR: + ResetComponent(componentProperties.armorBar.bar.placement, resetSize); + break; + } +} + +void CHudSA::SetComponentBarColor(const eHudComponent& component, float color) noexcept +{ + SColor newColor = TOCOLOR2SCOLOR(static_cast(color)); + GetHudBarRef(component).fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; +} + +void CHudSA::SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept +{ + GetHudBarRef(component).drawBlackBorder = draw; +} + +void CHudSA::SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept +{ + GetHudBarRef(component).drawPercentage = draw; +} + +void CHudSA::SetHealthBarBlinkingValue(float minHealth) noexcept +{ + componentProperties.hpBar.blinkingBarHP = minHealth; +} + +void CHudSA::RenderHealthBar(int x, int y) +{ + // Flash each 8 frames + bool isValidFrame = (pGame->GetSystemFrameCounter() & 8) == 0; + if (*itemToFlash == 4 && isValidFrame) // 4 = HEALTH_BAR + return; + + CPed* playerPed = pGame->GetPedContext(); + if (!playerPed || (playerPed->GetHealth() <= componentProperties.hpBar.blinkingBarHP && isValidFrame)) + return; + + // Save default position once + if (!componentProperties.hpBar.bar.placement.setDefaultXY) + { + componentProperties.hpBar.bar.placement.x = x; + componentProperties.hpBar.bar.placement.y = y; + componentProperties.hpBar.bar.placement.setDefaultXY = true; + } + + // Get player max health + float maxHealth = static_cast(pGame->GetPlayerInfo()->GetMaxHealth()); + + // Use custom position/size? + bool useCustomPosition = componentProperties.hpBar.bar.placement.useCustomPosition; + bool useCustomSize = componentProperties.hpBar.bar.placement.useCustomSize; + + // Calc bar width depending on MAX_HEALTH stat + double statModifier = ((double(__cdecl*)(int))FUNC_CStats_GetFatAndMuscleModifier)(10); + float totalWidth = ((useCustomSize ? componentProperties.hpBar.bar.placement.customWidth : componentProperties.hpBar.bar.placement.width) * maxHealth) / statModifier; + + // call CSprite2d::DrawBarChart + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.hpBar.bar.placement.customX : (useCustomSize ? componentProperties.hpBar.bar.placement.customWidth : componentProperties.hpBar.bar.placement.width) - totalWidth + x, useCustomPosition ? componentProperties.hpBar.bar.placement.customY : y, static_cast(totalWidth), static_cast(useCustomSize ? componentProperties.hpBar.bar.placement.customHeight : componentProperties.hpBar.bar.placement.height), playerPed->GetHealth() * 100.0f / maxHealth, false, componentProperties.hpBar.bar.drawPercentage, componentProperties.hpBar.bar.drawBlackBorder, componentProperties.hpBar.bar.fillColor, COLOR_BLACK); +} + +void CHudSA::RenderBreathBar(int x, int y) +{ + // Flash each 8 frames + if (*itemToFlash == 10 && (pGame->GetSystemFrameCounter() & 8) == 0) // 10 = BREATH_BAR + return; + + CPed* playerPed = pGame->GetPedContext(); + if (!playerPed) + return; + + // Save default position once + if (!componentProperties.breathBar.bar.placement.setDefaultXY) + { + componentProperties.breathBar.bar.placement.x = x; + componentProperties.breathBar.bar.placement.y = y; + componentProperties.breathBar.bar.placement.setDefaultXY = true; + } + + // Calc bar width depending on AIR_IN_LUNG stat + double statModifier = ((double(__cdecl*)(int))FUNC_CStats_GetFatAndMuscleModifier)(8); + + // Use custom position/size? + bool useCustomPosition = componentProperties.breathBar.bar.placement.useCustomPosition; + bool useCustomSize = componentProperties.breathBar.bar.placement.useCustomSize; + + // call CSprite2d::DrawBarChart + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.breathBar.bar.placement.customX : x, useCustomPosition ? componentProperties.breathBar.bar.placement.customY : y, static_cast(useCustomSize ? componentProperties.breathBar.bar.placement.customWidth : componentProperties.breathBar.bar.placement.width), static_cast(useCustomSize ? componentProperties.breathBar.bar.placement.customHeight : componentProperties.breathBar.bar.placement.height), playerPed->GetOxygenLevel() / statModifier * 100.0f, false, componentProperties.breathBar.bar.drawPercentage, componentProperties.breathBar.bar.drawBlackBorder, componentProperties.breathBar.bar.fillColor, COLOR_BLACK); +} + +void CHudSA::RenderArmorBar(int x, int y) +{ + // Flash each 8 frames + if (*itemToFlash == 3 && (pGame->GetSystemFrameCounter() & 8) == 0) // 3 = ARMOR_BAR + return; + + CPed* playerPed = pGame->GetPedContext(); + if (!playerPed || playerPed->GetArmor() < 1.0f) + return; + + // Save default position once + if (!componentProperties.armorBar.bar.placement.setDefaultXY) + { + componentProperties.armorBar.bar.placement.x = x; + componentProperties.armorBar.bar.placement.y = y; + componentProperties.armorBar.bar.placement.setDefaultXY = true; + } + + // Use custom position/size? + bool useCustomPosition = componentProperties.hpBar.bar.placement.useCustomPosition; + bool useCustomSize = componentProperties.hpBar.bar.placement.useCustomSize; + + // call CSprite2d::DrawBarChart + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.armorBar.bar.placement.customX : x, useCustomPosition ? componentProperties.armorBar.bar.placement.customY : y, static_cast(useCustomSize ? componentProperties.armorBar.bar.placement.customWidth : componentProperties.armorBar.bar.placement.width), static_cast(useCustomSize ? componentProperties.armorBar.bar.placement.customHeight : componentProperties.armorBar.bar.placement.height), playerPed->GetArmor() / static_cast(pGame->GetPlayerInfo()->GetMaxArmor()) * 100.0f, false, componentProperties.armorBar.bar.drawPercentage, componentProperties.armorBar.bar.drawBlackBorder, componentProperties.armorBar.bar.fillColor, COLOR_BLACK); +} + +static void _declspec(naked) HOOK_RenderHudBar() +{ + _asm + { + mov eax, [esp] + + push [esp+0Ch] // y + push [esp+0Ch] // x + + // Health bar + cmp eax, 0058EE9Fh + jz renderHealthBar + + cmp eax, 0058EF12h + jz renderHealthBar + + // Breath bar + cmp eax, 0058F136h + jz renderBreathBar + + cmp eax, 0058F1B2h + jz renderBreathBar + + // Armor bar + cmp eax, 0058EF70h + jz renderArmorBar + + cmp eax, 0058EFE3h + jz renderArmorBar + + jmp skip + + renderHealthBar: + call CHudSA::RenderHealthBar + jmp skip + + renderBreathBar: + call CHudSA::RenderBreathBar + jmp skip + + renderArmorBar: + call CHudSA::RenderArmorBar + jmp skip + + skip: + add esp, 8 + retn + } +} + +void CHudSA::StaticSetHooks() +{ + HookInstall(FUNC_RenderHealthBar, &HOOK_RenderHudBar, 11); + HookInstall(FUNC_RenderBreathBar, &HOOK_RenderHudBar, 11); + HookInstall(FUNC_RenderArmorBar, &HOOK_RenderHudBar, 11); +} diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index 11f1747b51..fd99e64bd3 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -13,19 +13,25 @@ #include #include +#include #define FUNC_Draw 0x58FAE0 #define VAR_DisableClock 0xBAA400 +// X +#define VAR_AspectRatioMultX 0x859520 +// Y #define VAR_AspectRatioMult 0x859524 + #define VAR_CameraCrosshairScale 0x866C74 #define FUNC_DrawAmmo 0x5893B0 #define FUNC_DrawWeaponIcon 0x58D7D0 -#define FUNC_PrintHealthForPlayer 0x589270 -#define FUNC_PrintBreathForPlayer 0x589190 -#define FUNC_PrintArmourForPlayer 0x5890A0 +#define FUNC_RenderHealthBar 0x589270 +#define FUNC_RenderBreathBar 0x589190 +#define FUNC_RenderArmorBar 0x5890A0 + #define FUNC_DrawVitalStats 0x589650 #define FUNC_DrawVehicleName 0x58AEA0 #define FUNC_DrawHelpText 0x58B6E0 @@ -36,9 +42,14 @@ #define FUNC_DrawWantedLevel 0x58D9A0 #define FUNC_DrawCrosshair 0x58E020 +#define FUNC_CStats_GetFatAndMuscleModifier 0x559AF0 +#define FUNC_CSprite2d_DrawBarChart 0x728640 + #define CODE_ShowMoney 0x58F47D #define VAR_CTheScripts_bDrawCrossHair 0xA44490 +#define VAR_RSGlobal 0xC17040 +#define VAR_ItemToFlash 0xBAB1DC struct SHudComponent { @@ -51,6 +62,84 @@ struct SHudComponent DWORD disabledData; }; +enum class eHudColour +{ + RED, + GREEN, + DARK_BLUE, + LIGHT_BLUE, + LIGHT_GRAY, + BLACK, + GOLD, + PURPLE, + DARK_GRAY, + DARK_RED, + DARK_GREEN, + CREAM, + NIGHT_BLUE, + BLUE, + YELLOW, +}; + +struct RsGlobal +{ + const char* appName; + std::int32_t maximumWidth; + std::int32_t maximumHeight; + std::int32_t frameLimit; + bool quit; + void* ps; + std::uint8_t keyboard[12]; // RsInputDevice + std::uint8_t mouse[12]; // RsInputDevice + std::uint8_t pad[12]; // RsInputDevice +}; + +struct ComponentPlacement +{ + // Original position & size + float x{0.0f}, y{0.0f}; // for getter function only + float width{0.0f}, height{0.0f}; + + // Custom position & size + float customX{0.0f}, customY{0.0f}; + float customWidth{0.0f}, customHeight{0.0f}; + + bool useCustomPosition{false}; + bool useCustomSize{false}; + bool setDefaultXY{false}; +}; + +struct HudBar +{ + ComponentPlacement placement; + RwColor fillColor{}; + bool drawBlackBorder{true}; + bool drawPercentage{false}; +}; + +struct HealthBar +{ + HudBar bar; + float blinkingBarHP{10.0f}; +}; + +struct BreathBar +{ + HudBar bar; +}; + +struct ArmorBar +{ + HudBar bar; +}; + +struct ComponentProperties +{ + HealthBar hpBar; + BreathBar breathBar; + ArmorBar armorBar; +}; + class CHudSA : public CHud { public: @@ -63,12 +152,44 @@ class CHudSA : public CHud void ResetComponentAdjustment(); bool IsCrosshairVisible(); + void SetComponentPlacementPosition(ComponentPlacement& placement, const CVector2D& position); + void SetComponentPlacementSize(ComponentPlacement& placement, const CVector2D& size); + + void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept override; + void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept override; + + void ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept override; + + void SetComponentBarColor(const eHudComponent& component, float color) noexcept override; + void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept override; + void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept override; + void SetHealthBarBlinkingValue(float minHealth) noexcept override; + + static RsGlobal* GetRSGlobal() noexcept { return rsGlobal; } + static RwColor GetHUDColour(const eHudColour& colour); + + static void StaticSetHooks(); + protected: void InitComponentList(); + void UpdateStreetchCalculations(); + void ResetComponent(ComponentPlacement& placement, bool resetSize) noexcept; + + static void RenderHealthBar(int x, int y); + static void RenderBreathBar(int x, int y); + static void RenderArmorBar(int x, int y); + + static HudBar& GetHudBarRef(const eHudComponent& component) noexcept; std::map m_HudComponentMap; float* m_pfAspectRatioMultiplicator; float* m_pfCameraCrosshairScale; float m_fSniperCrosshairScale; + + static RsGlobal* rsGlobal; + static std::int16_t* itemToFlash; + + static float calcStreetchX; + static float calcStreetchY; }; diff --git a/Client/game_sa/CPlayerInfoSA.h b/Client/game_sa/CPlayerInfoSA.h index fd73385f05..057c2927ab 100644 --- a/Client/game_sa/CPlayerInfoSA.h +++ b/Client/game_sa/CPlayerInfoSA.h @@ -268,4 +268,6 @@ class CPlayerInfoSA : public CPlayerInfo float GetBikeRearWheelDist() { return internalInterface->fBikeRearWheelDist; } DWORD GetBikeFrontWheelCounter() { return internalInterface->nBikeFrontWheelCounter; } float GetBikeFrontWheelDist() { return internalInterface->fBikeFrontWheelDist; } + std::uint8_t GetMaxHealth() { return internalInterface->MaxHealth; } + std::uint8_t GetMaxArmor() { return internalInterface->MaxArmour; } }; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 64708dea0c..ace6ec2010 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -111,6 +111,15 @@ ADD_ENUM(HUD_CROSSHAIR, "crosshair") ADD_ENUM(HUD_ALL, "all") IMPLEMENT_ENUM_END("hud-component") +IMPLEMENT_ENUM_CLASS_BEGIN(eHudComponentProperty) +ADD_ENUM(eHudComponentProperty::POSITION, "position") +ADD_ENUM(eHudComponentProperty::SIZE, "size") +ADD_ENUM(eHudComponentProperty::FILL_COLOR, "fillColor") +ADD_ENUM(eHudComponentProperty::DRAW_BLACK_BORDER, "drawBlackBorder") +ADD_ENUM(eHudComponentProperty::DRAW_PERCENTAGE, "drawPercentage") +ADD_ENUM(eHudComponentProperty::BLINKING_HP_VALUE, "blinkingValue") +IMPLEMENT_ENUM_CLASS_END("hud-component-property") + IMPLEMENT_ENUM_BEGIN(eAmbientSoundType) ADD_ENUM(AMBIENT_SOUND_GENERAL, "general") ADD_ENUM(AMBIENT_SOUND_GUNFIRE, "gunfire") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index e134a73bea..fffe9810b5 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -108,6 +108,7 @@ enum eDXVerticalAlign DECLARE_ENUM(eDXVerticalAlign); DECLARE_ENUM(eHudComponent); +DECLARE_ENUM_CLASS(eHudComponentProperty); enum eFieldOfViewMode { diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index e276a3ddf7..4b4247c9f3 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp @@ -40,6 +40,8 @@ void CLuaPlayerDefs::LoadFunctions() {"setPlayerNametagText", SetPlayerNametagText}, {"setPlayerNametagColor", SetPlayerNametagColor}, {"setPlayerNametagShowing", SetPlayerNametagShowing}, + {"setPlayerHudComponentProperty", ArgumentParser}, + {"resetPlayerHudComponentProperty", ArgumentParser}, // Community funcs {"getPlayerUserName", GetPlayerUserName}, @@ -77,6 +79,8 @@ void CLuaPlayerDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "isMapVisible", "isPlayerMapVisible"); lua_classfunction(luaVM, "isHudComponentVisible", "isPlayerHudComponentVisible"); lua_classfunction(luaVM, "toggleControl", "toggleControl"); + lua_classfunction(luaVM, "setHudComponentProperty", "setPlayerHudComponentProperty"); + lua_classfunction(luaVM, "resetHudComponentProperty", "resetPlayerHudComponentProperty"); lua_classfunction(luaVM, "create", "getPlayerFromName"); @@ -644,3 +648,168 @@ bool CLuaPlayerDefs::IsPlayerCrosshairVisible() { return g_pGame->GetHud()->IsCrosshairVisible(); } + +bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value) +{ + switch (property) + { + case eHudComponentProperty::POSITION: + { + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetComponentPosition(component, std::get(value)); + return true; + } + case eHudComponentProperty::SIZE: + { + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetComponentSize(component, std::get(value)); + return true; + } + case eHudComponentProperty::FILL_COLOR: + { + switch (component) + { + case HUD_HEALTH: + case HUD_ARMOUR: + case HUD_BREATH: + { + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetComponentBarColor(component, std::get(value)); + return true; + } + } + + break; + } + case eHudComponentProperty::DRAW_BLACK_BORDER: + { + switch (component) + { + case HUD_HEALTH: + case HUD_ARMOUR: + case HUD_BREATH: + { + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetComponentDrawBlackBorder(component, std::get(value)); + return true; + } + } + + break; + } + case eHudComponentProperty::DRAW_PERCENTAGE: + { + switch (component) + { + case HUD_HEALTH: + case HUD_ARMOUR: + case HUD_BREATH: + { + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetComponentDrawPercentage(component, std::get(value)); + return true; + } + } + + break; + } + case eHudComponentProperty::BLINKING_HP_VALUE: + { + if (component != HUD_HEALTH) + return false; + + if (!std::holds_alternative(value)) + return false; + + g_pGame->GetHud()->SetHealthBarBlinkingValue(std::get(value)); + return true; + } + } + + return false; +} + +bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) +{ + switch (property) + { + case eHudComponentProperty::POSITION: + { + g_pGame->GetHud()->ResetComponentPlacement(component, false); + return true; + } + case eHudComponentProperty::SIZE: + { + g_pGame->GetHud()->ResetComponentPlacement(component, true); + return true; + } + case eHudComponentProperty::FILL_COLOR: + { + switch (component) + { + case HUD_HEALTH: + // eHudColour::RED + g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(180, 25, 29, 255)); + return true; + case HUD_BREATH: + // eHudColour::LIGHT_BLUE + g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(172, 203, 241, 255)); + return true; + case HUD_ARMOUR: + // eHudColour::LIGHT_GRAY + g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(225, 225, 225, 255)); + return true; + } + + break; + } + case eHudComponentProperty::DRAW_BLACK_BORDER: + { + switch (component) + { + case HUD_HEALTH: + case HUD_BREATH: + case HUD_ARMOUR: + g_pGame->GetHud()->SetComponentDrawBlackBorder(component, true); + return true; + } + + break; + } + case eHudComponentProperty::DRAW_PERCENTAGE: + { + switch (component) + { + case HUD_HEALTH: + case HUD_BREATH: + case HUD_ARMOUR: + g_pGame->GetHud()->SetComponentDrawPercentage(component, false); + return true; + } + + break; + } + case eHudComponentProperty::BLINKING_HP_VALUE: + { + if (component == HUD_HEALTH) + { + g_pGame->GetHud()->SetHealthBarBlinkingValue(10.0f); + return true; + } + + break; + } + } + + return false; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h index 1a2895ed3d..8baca7900c 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h @@ -41,6 +41,8 @@ class CLuaPlayerDefs : public CLuaDefs LUA_DECLARE(SetPlayerNametagText); LUA_DECLARE(SetPlayerNametagColor); LUA_DECLARE(SetPlayerNametagShowing); + static bool SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value); + static bool ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property); // Community funcs LUA_DECLARE(GetPlayerUserName); diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index 2314fdad0e..4aa3a864cf 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -156,6 +156,7 @@ class __declspec(novtable) CGame virtual CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false) = 0; virtual DWORD GetSystemTime() = 0; + virtual int GetSystemFrameCounter() = 0; virtual bool IsAtMenu() = 0; virtual void StartGame() = 0; virtual void SetSystemState(eSystemState State) = 0; diff --git a/Client/sdk/game/CHud.h b/Client/sdk/game/CHud.h index af37d4a4cd..208a6e8a37 100644 --- a/Client/sdk/game/CHud.h +++ b/Client/sdk/game/CHud.h @@ -10,6 +10,7 @@ *****************************************************************************/ #pragma once +#include "CVector2D.h" enum eHudComponent { @@ -32,6 +33,16 @@ enum eHudComponent HUD_HELP_TEXT, }; +enum class eHudComponentProperty +{ + FILL_COLOR, + DRAW_BLACK_BORDER, + DRAW_PERCENTAGE, + BLINKING_HP_VALUE, + POSITION, + SIZE, +}; + class CHud { public: @@ -42,4 +53,13 @@ class CHud virtual void AdjustComponents(float fAspectRatio) = 0; virtual void ResetComponentAdjustment() = 0; virtual bool IsCrosshairVisible() = 0; + + // Hud properties + virtual void SetComponentBarColor(const eHudComponent& component, float color) noexcept = 0; + virtual void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept = 0; + virtual void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept = 0; + virtual void SetHealthBarBlinkingValue(float minHealth) noexcept = 0; + virtual void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept = 0; + virtual void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept = 0; + virtual void ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept = 0; }; diff --git a/Client/sdk/game/CPlayerInfo.h b/Client/sdk/game/CPlayerInfo.h index 91b7e16d6c..44f0e08787 100644 --- a/Client/sdk/game/CPlayerInfo.h +++ b/Client/sdk/game/CPlayerInfo.h @@ -38,4 +38,6 @@ class CPlayerInfo virtual float GetBikeRearWheelDist() = 0; virtual DWORD GetBikeFrontWheelCounter() = 0; virtual float GetBikeFrontWheelDist() = 0; + virtual std::uint8_t GetMaxHealth() = 0; + virtual std::uint8_t GetMaxArmor() = 0; }; diff --git a/Shared/sdk/SharedUtil.Defines.h b/Shared/sdk/SharedUtil.Defines.h index 580335e61b..bccd2e8f2f 100644 --- a/Shared/sdk/SharedUtil.Defines.h +++ b/Shared/sdk/SharedUtil.Defines.h @@ -166,6 +166,8 @@ #define ZERO_POD_STRUCT(ptr) \ memset ( ptr, 0, sizeof(*(ptr)) ) +#define mask(n) ((1 << (n)) - 1) + // printf/wprintf helpers // // http://www.firstobject.com/wchar_t-string-on-linux-osx-windows.htm diff --git a/Shared/sdk/SharedUtil.Misc.h b/Shared/sdk/SharedUtil.Misc.h index d64f155a7c..bd8f7bfe15 100644 --- a/Shared/sdk/SharedUtil.Misc.h +++ b/Shared/sdk/SharedUtil.Misc.h @@ -549,6 +549,20 @@ namespace SharedUtil inline SColor COLOR_ARGB(unsigned char A, unsigned char R, unsigned char G, unsigned char B) { return SColorRGBA(R, G, B, A); } inline SColor COLOR_ABGR(unsigned char A, unsigned char B, unsigned char G, unsigned char R) { return SColorRGBA(R, G, B, A); } + // + // Convert tocolor value to SColor + // + inline SColor TOCOLOR2SCOLOR(std::uint32_t colorValue) + { + SColor color; + color.R = static_cast((colorValue >> 16) & mask(8)); + color.G = static_cast((colorValue >> 8) & mask(8)); + color.B = static_cast((colorValue >> 0) & mask(8)); + color.A = static_cast((colorValue >> 24) & mask(8)); + + return color; + } + // // Cross platform critical section // From 3d587a279f882faf427e6fc23ae4038e1c07cec7 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 22 Dec 2024 08:03:57 +0100 Subject: [PATCH 2/5] Update & cleanups --- Client/game_sa/CFontSA.cpp | 172 +++++++++++ Client/game_sa/CFontSA.h | 135 ++++++++ Client/game_sa/CGameSA.h | 2 +- Client/game_sa/CHudSA.cpp | 292 ++++++++++++++---- Client/game_sa/CHudSA.h | 121 +++++--- Client/game_sa/CPlayerInfoSA.h | 4 +- Client/game_sa/HookSystem.cpp | 7 + Client/game_sa/HookSystem.h | 2 + .../logic/lua/CLuaFunctionParseHelpers.cpp | 21 ++ .../logic/lua/CLuaFunctionParseHelpers.h | 2 + .../logic/luadefs/CLuaPlayerDefs.cpp | 262 ++++++++++------ .../deathmatch/logic/luadefs/CLuaPlayerDefs.h | 2 +- Client/sdk/game/CGame.h | 2 +- Client/sdk/game/CHud.h | 51 ++- Client/sdk/game/CPlayerInfo.h | 4 +- 15 files changed, 874 insertions(+), 205 deletions(-) create mode 100644 Client/game_sa/CFontSA.cpp create mode 100644 Client/game_sa/CFontSA.h diff --git a/Client/game_sa/CFontSA.cpp b/Client/game_sa/CFontSA.cpp new file mode 100644 index 0000000000..4ff40aeb54 --- /dev/null +++ b/Client/game_sa/CFontSA.cpp @@ -0,0 +1,172 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CFontSA.cpp + * PURPOSE: Font class layer + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CFontSA.h" + +void CFontSA::PrintChar(float x, float y, char character) +{ + // Call CFont::PrintChar + ((void(_cdecl*)(float, float, char))FUNC_CFont_PrintChar)(x, y, character); +} + +void CFontSA::PrintString(float x, float y, const char* text) +{ + // Call CFont::PrintString + ((void(__cdecl*)(float, float, const char*))FUNC_CFont_PrintString)(x, y, text); +} + +void CFontSA::PrintStringFromBottom(float x, float y, const char* text) +{ + // Call CFont::PrintStringFromBottom + ((void(__cdecl*)(float, float, const char*))FUNC_CFont_PrintStringFromBottom)(x, y, text); +} + +void CFontSA::SetScale(float w, float h) +{ + // Call CFont::SetScale + ((void(__cdecl*)(float, float))FUNC_CFont_SetScale)(w, h); +} + +void CFontSA::SetScale(const CVector2D& scale) +{ + SetScale(scale.fX, scale.fY); +} + +void CFontSA::SetSlantRefPoint(float x, float y) +{ + // Call CFont::SetSlantRefPoint + ((void(__cdecl*)(float, float))FUNC_CFont_SetSlantRefPoint)(x, y); +} + +void CFontSA::SetSlant(float slant) +{ + // Call CFont::SetSlant + ((void(__cdecl*)(float))FUNC_CFont_SetSlant)(slant); +} + +void CFontSA::SetColor(const RwColor& color) +{ + // Call CFont::SetColor + ((void(__cdecl*)(RwColor))FUNC_CFont_SetColor)(color); +} + +void CFontSA::SetDropColor(const RwColor& color) +{ + // Call CFont::SetDropColor + ((void(__cdecl*)(RwColor))FUNC_CFont_SetDropColor)(color); +} + +void CFontSA::SetFontStyle(const eFontStyle& style) +{ + // Call CFont::SetFontStyle + ((void(__cdecl*)(std::uint16_t))FUNC_CFont_SetStyle)(static_cast(style)); +} + +void CFontSA::SetWrapX(float wrapx) +{ + // Call CFont::SetWrapx + ((void(__cdecl*)(float))FUNC_CFont_SetWrapX)(wrapx); +} + +void CFontSA::SetRightJustifyWrap(float wrap) +{ + // Call CFont::SetRightJustifyWrap + ((void(__cdecl*)(float))FUNC_CFont_SetRightJustifyWrap)(wrap); +} + +void CFontSA::SetCentreSize(float size) +{ + // Call CFont::SetCentreSize + ((void(__cdecl*)(float))FUNC_CFont_SetCentreSize)(size); +} + +void CFontSA::SetDropShadowPosition(std::int16_t offset) +{ + // Call CFont::SetDropShadowPosition + ((void(__cdecl*)(std::int16_t))FUNC_CFont_SetDropShadowPosition)(offset); +} + +void CFontSA::SetEdge(std::int16_t edgeSize) +{ + // Call CFont::SetEdge + ((void(__cdecl*)(std::int16_t))FUNC_CFont_SetEdge)(edgeSize); +} + +void CFontSA::SetProportional(bool enable) +{ + // Call CFont::SetProportional + ((void(__cdecl*)(bool))FUNC_CFont_SetProportional)(enable); +} + +void CFontSA::SetBackground(bool enable, bool includeWrap) +{ + // Call CFont::SetBackground + ((void(__cdecl*)(bool, bool))FUNC_CFont_SetBackground)(enable, includeWrap); +} + +void CFontSA::SetBackgroundColor(const RwColor& color) +{ + // Call CFont::SetBackgroundColor + ((void(__cdecl*)(RwColor))FUNC_CFont_SetBackgroundColor)(color); +} + +void CFontSA::SetJustify(bool enable) +{ + // Call CFont::SetJustify + ((void(__cdecl*)(bool))FUNC_CFont_SetJustify)(enable); +} + +void CFontSA::SetOrientation(const eFontAlignment& alignment) +{ + // Call CFont::SetOrientation + ((void(__cdecl*)(eFontAlignment))FUNC_CFont_SetOrientation)(alignment); +} + +float CFontSA::GetStringWidth(const char* string, bool spaces, bool scriptValues) +{ + // Call CFont::GetStringWidth + return ((float(__cdecl*)(const char*, bool, bool))FUNC_CFont_GetStringWidth)(string, spaces, scriptValues); +} + +std::int16_t CFontSA::GetNumberLines(float x, float y, const char* text) +{ + // Call CFont::GetNumberLines + return ((std::int16_t(__cdecl*)(float, float, const char*))FUNC_CFont_GetNumberLines)(x, y, text); +} + +eFontAlignment CFontSA::GetOrientation() +{ + bool centerAlign = *reinterpret_cast(VAR_CFont_CenterAlign); + bool rightAlign = *reinterpret_cast(VAR_CFont_RightAlign); + + if (centerAlign) + return eFontAlignment::ALIGN_CENTER; + else if (rightAlign) + return eFontAlignment::ALIGN_RIGHT; + + return eFontAlignment::ALIGN_LEFT; +} + +eFontStyle CFontSA::GetFontStyle() +{ + std::uint8_t style = *reinterpret_cast(VAR_CFont_FontStyle); + + switch (style) + { + case 0: + return *reinterpret_cast(VAR_CFont_TextureID); + case 1: + return eFontStyle::FONT_PRICEDOWN; + case 2: + return eFontStyle::FONT_MENU; + } +} diff --git a/Client/game_sa/CFontSA.h b/Client/game_sa/CFontSA.h new file mode 100644 index 0000000000..c2da521bd3 --- /dev/null +++ b/Client/game_sa/CFontSA.h @@ -0,0 +1,135 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CFontSA.h + * PURPOSE: Header file for font class + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once +#include +#include +#include + +#define FUNC_CFont_PrintChar 0x718A10 +#define FUNC_CFont_PrintString 0x71A700 +#define FUNC_CFont_PrintStringFromBottom 0x71A820 + +#define FUNC_CFont_SetScale 0x719380 + +#define FUNC_CFont_SetSlantRefPoint 0x719400 +#define FUNC_CFont_SetSlant 0x719420 + +#define FUNC_CFont_SetStyle 0x719490 +#define FUNC_CFont_SetCentreSize 0x7194E0 + +#define FUNC_CFont_SetWrapX 0x7194D0 +#define FUNC_CFont_SetRightJustifyWrap 0x7194F0 + +#define FUNC_CFont_SetColor 0x719430 +#define FUNC_CFont_SetDropColor 0x719510 + +#define FUNC_CFont_SetDropShadowPosition 0x719570 +#define FUNC_CFont_SetEdge 0x719590 + +#define FUNC_CFont_SetProportional 0x7195B0 + +#define FUNC_CFont_SetBackground 0x7195C0 +#define FUNC_CFont_SetBackgroundColor 0x7195E0 + +#define FUNC_CFont_SetJustify 0x719600 +#define FUNC_CFont_SetOrientation 0x719610 + +#define FUNC_CFont_GetStringWidth 0x71A0E0 +#define FUNC_CFont_GetNumberLines 0x71A5E0 + +#define VAR_CFont_Scale 0xC71A64 +#define VAR_CFont_Color 0xC71A60 + +#define VAR_CFont_Slant 0xC71A6C +#define VAR_CFont_SlantRefPoint 0xC71A70 + +#define VAR_CFont_Justify 0xC71A78 +#define VAR_CFont_RightJustifyWrap 0xC71A90 + +#define VAR_CFont_CenterAlign 0xC71A79 +#define VAR_CFont_RightAlign 0xC71A7A + +#define VAR_CFont_Background 0xC71A7B +#define VAR_CFont_BackgroundIncludeWrap 0xC71A7C +#define VAR_CFont_BackgroundColor 0xC71A84 + +#define VAR_CFont_Proportional 0xC71A7D +#define VAR_CFont_Wrapx 0xC71A88 +#define VAR_CFont_CentreSize 0xC71A8C + +#define VAR_CFont_FontStyle 0xC71A95 +#define VAR_CFont_TextureID 0xC71A94 +#define VAR_CFont_Shadow 0xC71A96 + +#define VAR_CFont_DropColor 0xC71A97 +#define VAR_CFont_Edge 0xC71A9B + +class CFontSA +{ +public: + static void PrintChar(float x, float y, char character); + static void PrintString(float x, float y, const char* text); + static void PrintStringFromBottom(float x, float y, const char* text); + + static void SetScale(float w, float h); + static void SetScale(const CVector2D& scale); + + static void SetSlantRefPoint(float x, float y); + static void SetSlant(float slant); + + static void SetColor(const RwColor& color); + static void SetDropColor(const RwColor& color); + + static void SetFontStyle(const eFontStyle& style); + static void SetCentreSize(float size); + + static void SetWrapX(float wrapx); + static void SetRightJustifyWrap(float wrap); + + static void SetDropShadowPosition(std::int16_t offset); + static void SetEdge(std::int16_t edgeSize); // outline + + static void SetProportional(bool enable); + + static void SetBackground(bool enable, bool includeWrap); + static void SetBackgroundColor(const RwColor& color); + + static void SetJustify(bool enable); + static void SetOrientation(const eFontAlignment& alignment); + + static float GetStringWidth(const char* string, bool spaces, bool scriptValues = false); + static std::int16_t GetNumberLines(float x, float y, const char* text); + + static CVector2D GetScale() { return *reinterpret_cast(VAR_CFont_Scale); } + static RwColor GetColor() { return *reinterpret_cast(VAR_CFont_Color); } + + static float GetSlant() { return *reinterpret_cast(VAR_CFont_Slant); } + static CVector2D GetSlantRefPoint() { return *reinterpret_cast(VAR_CFont_SlantRefPoint); } + + static bool IsFontJustify() { return *reinterpret_cast(VAR_CFont_Justify); } + static eFontAlignment GetOrientation(); + + static bool IsBackgroundEnabled() { return *reinterpret_cast(VAR_CFont_Background); } + static bool IsBackgroundWrapIncluded() { return *reinterpret_cast(VAR_CFont_BackgroundIncludeWrap); } + static RwColor GetBackgroundColor() { return *reinterpret_cast(VAR_CFont_BackgroundColor); } + + static bool IsProportional() { return *reinterpret_cast(VAR_CFont_Proportional); } + + static float GetWrapX() { return *reinterpret_cast(VAR_CFont_Wrapx); } + static float GetCentreSize() { return *reinterpret_cast(VAR_CFont_CentreSize); } + static float GetRightJustifyWrap() { return *reinterpret_cast(VAR_CFont_RightJustifyWrap); } + + static eFontStyle GetFontStyle(); + + static float GetEdge() { return *reinterpret_cast(VAR_CFont_Edge); } + static float GetDropdownShadow() { return *reinterpret_cast(VAR_CFont_Shadow); } +}; diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index f945fe5c20..b4a9f4cd16 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -190,7 +190,7 @@ class CGameSA : public CGame int32_t GetCountOfAllFileIDs() { return (*(char**)(0x5B8AFA + 2) - *(char**)(0x5B8B08 + 6)) / sizeof(CStreamingInfo); } DWORD GetSystemTime() { return *(DWORD*)0xB7CB84; } // CTimer::m_snTimeInMilliseconds - int GetSystemFrameCounter() { return *(int*)0xB7CB4C; } // CTimer::m_FrameCounter + int GetSystemFrameCounter() const { return *(int*)0xB7CB4C; } // CTimer::m_FrameCounter bool IsAtMenu() { return *(unsigned long*)0xBA677B != 0; } // FrontEndMenuManager + 0x33 diff --git a/Client/game_sa/CHudSA.cpp b/Client/game_sa/CHudSA.cpp index 630438bab2..cc0eec2b26 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -28,8 +28,17 @@ std::int16_t* CHudSA::itemToFlash = reinterpret_cast(VAR_ItemToFl float CHudSA::calcStreetchX = 0.0f; float CHudSA::calcStreetchY = 0.0f; +float CHudSA::blinkingBarHPValue = 10.0f; -constexpr RwColor COLOR_BLACK = RwColor{0, 0, 0, 0}; +constexpr RwColor COLOR_BLACK = RwColor{0, 0, 0, 255}; + +// default component properties +std::unordered_map defaultComponentProperties = { + {HUD_HEALTH, {CHudSA::GetHUDColour(eHudColour::RED)}}, + {HUD_BREATH, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE)}}, + {HUD_CLOCK, {CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}}, + {HUD_MONEY, {CHudSA::GetHUDColour(eHudColour::GREEN), CHudSA::GetHUDColour(eHudColour::RED), false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}} +}; CHudSA::CHudSA() { @@ -53,10 +62,12 @@ CHudSA::CHudSA() MemPut(0x53E488 + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x53E4BF + 2, (DWORD)&m_fSniperCrosshairScale); - // Initalize default colors - componentProperties.hpBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::RED); - componentProperties.breathBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE); - componentProperties.armorBar.bar.fillColor = CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY); + // Initalize default data + componentProperties.hpBar = MapGet(defaultComponentProperties, HUD_HEALTH); + componentProperties.breathBar = MapGet(defaultComponentProperties, HUD_BREATH); + componentProperties.armorBar = MapGet(defaultComponentProperties, HUD_ARMOUR); + componentProperties.clock = MapGet(defaultComponentProperties, HUD_CLOCK); + componentProperties.money = MapGet(defaultComponentProperties, HUD_MONEY); } void CHudSA::Disable(bool bDisabled) @@ -172,20 +183,30 @@ void CHudSA::UpdateStreetchCalculations() calcStreetchX = rsGlobal->maximumWidth * (*reinterpret_cast(VAR_AspectRatioMultX)); calcStreetchY = rsGlobal->maximumHeight * (*m_pfAspectRatioMultiplicator); - ComponentPlacement& hpPlacement = componentProperties.hpBar.bar.placement; + SComponentPlacement& hpPlacement = componentProperties.hpBar.placement; hpPlacement.height = calcStreetchY * 9.0f; hpPlacement.width = calcStreetchX * 109.0f; hpPlacement.setDefaultXY = false; - ComponentPlacement& breathPlacement = componentProperties.breathBar.bar.placement; + SComponentPlacement& breathPlacement = componentProperties.breathBar.placement; breathPlacement.height = calcStreetchY * 9.0f; breathPlacement.width = calcStreetchX * 62.0f; breathPlacement.setDefaultXY = false; - ComponentPlacement& armorPlacement = componentProperties.armorBar.bar.placement; + SComponentPlacement& armorPlacement = componentProperties.armorBar.placement; armorPlacement.height = calcStreetchY * 9.0f; armorPlacement.width = calcStreetchX * 62.0f; armorPlacement.setDefaultXY = false; + + SComponentPlacement& clockPlacement = componentProperties.clock.placement; + clockPlacement.height = calcStreetchY * 1.1f; + clockPlacement.width = calcStreetchX * 0.55f; + clockPlacement.setDefaultXY = false; + + SComponentPlacement& moneyPlacement = componentProperties.money.placement; + moneyPlacement.height = calcStreetchY * 1.1f; + moneyPlacement.width = calcStreetchX * 0.55f; + moneyPlacement.setDefaultXY = false; } // @@ -271,7 +292,36 @@ bool CHudSA::IsCrosshairVisible() return specialAiming || simpleAiming || crossHairType > 0; } -RwColor CHudSA::GetHUDColour(const eHudColour& colour) +bool CHudSA::IsComponentBar(const eHudComponent& component) const noexcept +{ + switch (component) + { + case HUD_HEALTH: + case HUD_ARMOUR: + case HUD_BREATH: + return true; + } + + return false; +} + +bool CHudSA::IsComponentText(const eHudComponent& component) const noexcept +{ + switch (component) + { + case HUD_CLOCK: + case HUD_MONEY: + case HUD_AMMO: + case HUD_AREA_NAME: + case HUD_VEHICLE_NAME: + case HUD_RADIO: + return true; + } + + return false; +} + +RwColor CHudSA::GetHUDColour(const eHudColour& colour) noexcept { switch (colour) { @@ -310,27 +360,14 @@ RwColor CHudSA::GetHUDColour(const eHudColour& colour) } } -HudBar& CHudSA::GetHudBarRef(const eHudComponent& component) noexcept -{ - switch (component) - { - case HUD_HEALTH: - return componentProperties.hpBar.bar; - case HUD_BREATH: - return componentProperties.breathBar.bar; - case HUD_ARMOUR: - return componentProperties.armorBar.bar; - } -} - -void CHudSA::SetComponentPlacementPosition(ComponentPlacement& placement, const CVector2D& position) +void CHudSA::SetComponentPlacementPosition(SComponentPlacement& placement, const CVector2D& position) noexcept { placement.customX = position.fX; placement.customY = position.fY; placement.useCustomPosition = true; } -void CHudSA::SetComponentPlacementSize(ComponentPlacement& placement, const CVector2D& size) +void CHudSA::SetComponentPlacementSize(SComponentPlacement& placement, const CVector2D& size) noexcept { placement.customWidth = size.fX; placement.customHeight = size.fY; @@ -342,13 +379,13 @@ void CHudSA::SetComponentPosition(const eHudComponent& component, const CVector2 switch (component) { case HUD_BREATH: - SetComponentPlacementPosition(componentProperties.breathBar.bar.placement, position); + SetComponentPlacementPosition(componentProperties.breathBar.placement, position); break; case HUD_HEALTH: - SetComponentPlacementPosition(componentProperties.hpBar.bar.placement, position); + SetComponentPlacementPosition(componentProperties.hpBar.placement, position); break; case HUD_ARMOUR: - SetComponentPlacementPosition(componentProperties.armorBar.bar.placement, position); + SetComponentPlacementPosition(componentProperties.armorBar.placement, position); break; } } @@ -358,18 +395,18 @@ void CHudSA::SetComponentSize(const eHudComponent& component, const CVector2D& s switch (component) { case HUD_BREATH: - SetComponentPlacementSize(componentProperties.breathBar.bar.placement, size); + SetComponentPlacementSize(componentProperties.breathBar.placement, size); break; case HUD_HEALTH: - SetComponentPlacementSize(componentProperties.hpBar.bar.placement, size); + SetComponentPlacementSize(componentProperties.hpBar.placement, size); break; case HUD_ARMOUR: - SetComponentPlacementSize(componentProperties.armorBar.bar.placement, size); + SetComponentPlacementSize(componentProperties.armorBar.placement, size); break; } } -void CHudSA::ResetComponent(ComponentPlacement& placement, bool resetSize) noexcept +void CHudSA::ResetComponent(SComponentPlacement& placement, bool resetSize) noexcept { if (resetSize) { @@ -385,6 +422,54 @@ void CHudSA::ResetComponent(ComponentPlacement& placement, bool resetSize) noexc } } +void CHudSA::ResetComponentFontData(const eHudComponent& component, const eHudComponentProperty& property) noexcept +{ + if (!IsComponentText(component)) + return; + + auto& ref = GetHudComponentRef(component); + if (!MapFind(defaultComponentProperties, component)) + return; + + const auto& defaultRef = MapGet(defaultComponentProperties, component); + + switch (property) + { + case eHudComponentProperty::TEXT_OUTLINE: + ref.textOutline = defaultRef.textOutline; + break; + case eHudComponentProperty::TEXT_SHADOW: + ref.textShadow = defaultRef.textShadow; + break; + case eHudComponentProperty::TEXT_STYLE: + ref.style = defaultRef.style; + break; + case eHudComponentProperty::TEXT_ALIGNMENT: + ref.alignment = defaultRef.alignment; + break; + case eHudComponentProperty::TEXT_PROPORTIONAL: + ref.proportional = defaultRef.proportional; + break; + } +} + +SHudComponentData& CHudSA::GetHudComponentRef(const eHudComponent& component) const noexcept +{ + switch (component) + { + case HUD_HEALTH: + return componentProperties.hpBar; + case HUD_BREATH: + return componentProperties.breathBar; + case HUD_ARMOUR: + return componentProperties.armorBar; + case HUD_CLOCK: + return componentProperties.clock; + case HUD_MONEY: + return componentProperties.money; + } +} + void CHudSA::ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept { switch (component) @@ -402,36 +487,45 @@ void CHudSA::ResetComponentPlacement(const eHudComponent& component, bool resetS break; } case HUD_HEALTH: - ResetComponent(componentProperties.hpBar.bar.placement, resetSize); + ResetComponent(componentProperties.hpBar.placement, resetSize); break; case HUD_BREATH: - ResetComponent(componentProperties.breathBar.bar.placement, resetSize); + ResetComponent(componentProperties.breathBar.placement, resetSize); break; case HUD_ARMOUR: - ResetComponent(componentProperties.armorBar.bar.placement, resetSize); + ResetComponent(componentProperties.armorBar.placement, resetSize); break; } } -void CHudSA::SetComponentBarColor(const eHudComponent& component, float color) noexcept +void CHudSA::SetComponentColor(const eHudComponent& component, std::uint32_t color, bool secondColor) noexcept { - SColor newColor = TOCOLOR2SCOLOR(static_cast(color)); - GetHudBarRef(component).fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; -} + SColor newColor = TOCOLOR2SCOLOR(color); -void CHudSA::SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept -{ - GetHudBarRef(component).drawBlackBorder = draw; + if (!secondColor) + GetHudComponentRef(component).fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; + else + GetHudComponentRef(component).fillColor_Second = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; } -void CHudSA::SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept +void CHudSA::ResetComponentColor(const eHudComponent& component, bool secondColor) noexcept { - GetHudBarRef(component).drawPercentage = draw; + auto& componentData = GetHudComponentRef(component); + if (!MapFind(defaultComponentProperties, component)) + return; + + const auto& defaultRef = MapGet(defaultComponentProperties, component); + + if (!secondColor) + componentData.fillColor = defaultRef.fillColor; + else + componentData.fillColor_Second = defaultRef.fillColor_Second; } -void CHudSA::SetHealthBarBlinkingValue(float minHealth) noexcept +void CHudSA::SetComponentFontDropColor(const eHudComponent& component, std::uint32_t color) noexcept { - componentProperties.hpBar.blinkingBarHP = minHealth; + SColor newColor = TOCOLOR2SCOLOR(color); + GetHudComponentRef(component).dropColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; } void CHudSA::RenderHealthBar(int x, int y) @@ -442,30 +536,36 @@ void CHudSA::RenderHealthBar(int x, int y) return; CPed* playerPed = pGame->GetPedContext(); - if (!playerPed || (playerPed->GetHealth() <= componentProperties.hpBar.blinkingBarHP && isValidFrame)) + if (!playerPed || (playerPed->GetHealth() <= blinkingBarHPValue && isValidFrame)) return; // Save default position once - if (!componentProperties.hpBar.bar.placement.setDefaultXY) + if (!componentProperties.hpBar.placement.setDefaultXY) { - componentProperties.hpBar.bar.placement.x = x; - componentProperties.hpBar.bar.placement.y = y; - componentProperties.hpBar.bar.placement.setDefaultXY = true; + componentProperties.hpBar.placement.x = x; + componentProperties.hpBar.placement.y = y; + componentProperties.hpBar.placement.setDefaultXY = true; } // Get player max health float maxHealth = static_cast(pGame->GetPlayerInfo()->GetMaxHealth()); // Use custom position/size? - bool useCustomPosition = componentProperties.hpBar.bar.placement.useCustomPosition; - bool useCustomSize = componentProperties.hpBar.bar.placement.useCustomSize; + bool useCustomPosition = componentProperties.hpBar.placement.useCustomPosition; + bool useCustomSize = componentProperties.hpBar.placement.useCustomSize; + + float barWidth = useCustomSize ? componentProperties.hpBar.placement.customWidth : componentProperties.hpBar.placement.width; // Calc bar width depending on MAX_HEALTH stat double statModifier = ((double(__cdecl*)(int))FUNC_CStats_GetFatAndMuscleModifier)(10); - float totalWidth = ((useCustomSize ? componentProperties.hpBar.bar.placement.customWidth : componentProperties.hpBar.bar.placement.width) * maxHealth) / statModifier; + float totalWidth = (barWidth * maxHealth) / statModifier; + + float posX = useCustomPosition ? componentProperties.hpBar.placement.customX : (barWidth - totalWidth + x); + float posY = useCustomPosition ? componentProperties.hpBar.placement.customY : y; + std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.hpBar.placement.customHeight : componentProperties.hpBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.hpBar.bar.placement.customX : (useCustomSize ? componentProperties.hpBar.bar.placement.customWidth : componentProperties.hpBar.bar.placement.width) - totalWidth + x, useCustomPosition ? componentProperties.hpBar.bar.placement.customY : y, static_cast(totalWidth), static_cast(useCustomSize ? componentProperties.hpBar.bar.placement.customHeight : componentProperties.hpBar.bar.placement.height), playerPed->GetHealth() * 100.0f / maxHealth, false, componentProperties.hpBar.bar.drawPercentage, componentProperties.hpBar.bar.drawBlackBorder, componentProperties.hpBar.bar.fillColor, COLOR_BLACK); + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, static_cast(totalWidth), barHeight, playerPed->GetHealth() * 100.0f / maxHealth, false, componentProperties.hpBar.drawPercentage, componentProperties.hpBar.drawBlackBorder, componentProperties.hpBar.fillColor, COLOR_BLACK); } void CHudSA::RenderBreathBar(int x, int y) @@ -479,22 +579,27 @@ void CHudSA::RenderBreathBar(int x, int y) return; // Save default position once - if (!componentProperties.breathBar.bar.placement.setDefaultXY) + if (!componentProperties.breathBar.placement.setDefaultXY) { - componentProperties.breathBar.bar.placement.x = x; - componentProperties.breathBar.bar.placement.y = y; - componentProperties.breathBar.bar.placement.setDefaultXY = true; + componentProperties.breathBar.placement.x = x; + componentProperties.breathBar.placement.y = y; + componentProperties.breathBar.placement.setDefaultXY = true; } // Calc bar width depending on AIR_IN_LUNG stat double statModifier = ((double(__cdecl*)(int))FUNC_CStats_GetFatAndMuscleModifier)(8); // Use custom position/size? - bool useCustomPosition = componentProperties.breathBar.bar.placement.useCustomPosition; - bool useCustomSize = componentProperties.breathBar.bar.placement.useCustomSize; + bool useCustomPosition = componentProperties.breathBar.placement.useCustomPosition; + bool useCustomSize = componentProperties.breathBar.placement.useCustomSize; + + float posX = useCustomPosition ? componentProperties.breathBar.placement.customX : x; + float posY = useCustomPosition ? componentProperties.breathBar.placement.customY : y; + std::uint16_t barWidth = static_cast(useCustomSize ? componentProperties.breathBar.placement.customWidth : componentProperties.breathBar.placement.width); + std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.breathBar.placement.customHeight : componentProperties.breathBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.breathBar.bar.placement.customX : x, useCustomPosition ? componentProperties.breathBar.bar.placement.customY : y, static_cast(useCustomSize ? componentProperties.breathBar.bar.placement.customWidth : componentProperties.breathBar.bar.placement.width), static_cast(useCustomSize ? componentProperties.breathBar.bar.placement.customHeight : componentProperties.breathBar.bar.placement.height), playerPed->GetOxygenLevel() / statModifier * 100.0f, false, componentProperties.breathBar.bar.drawPercentage, componentProperties.breathBar.bar.drawBlackBorder, componentProperties.breathBar.bar.fillColor, COLOR_BLACK); + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, barWidth, barHeight, playerPed->GetOxygenLevel() / statModifier * 100.0f, false, componentProperties.breathBar.drawPercentage, componentProperties.breathBar.drawBlackBorder, componentProperties.breathBar.fillColor, COLOR_BLACK); } void CHudSA::RenderArmorBar(int x, int y) @@ -508,19 +613,67 @@ void CHudSA::RenderArmorBar(int x, int y) return; // Save default position once - if (!componentProperties.armorBar.bar.placement.setDefaultXY) + if (!componentProperties.armorBar.placement.setDefaultXY) { - componentProperties.armorBar.bar.placement.x = x; - componentProperties.armorBar.bar.placement.y = y; - componentProperties.armorBar.bar.placement.setDefaultXY = true; + componentProperties.armorBar.placement.x = x; + componentProperties.armorBar.placement.y = y; + componentProperties.armorBar.placement.setDefaultXY = true; } // Use custom position/size? - bool useCustomPosition = componentProperties.hpBar.bar.placement.useCustomPosition; - bool useCustomSize = componentProperties.hpBar.bar.placement.useCustomSize; + bool useCustomPosition = componentProperties.hpBar.placement.useCustomPosition; + bool useCustomSize = componentProperties.hpBar.placement.useCustomSize; + + float posX = useCustomPosition ? componentProperties.armorBar.placement.customX : x; + float posY = useCustomPosition ? componentProperties.armorBar.placement.customY : y; + std::uint16_t barWidth = static_cast(useCustomSize ? componentProperties.armorBar.placement.customWidth : componentProperties.armorBar.placement.width); + std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.armorBar.placement.customHeight : componentProperties.armorBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(useCustomPosition ? componentProperties.armorBar.bar.placement.customX : x, useCustomPosition ? componentProperties.armorBar.bar.placement.customY : y, static_cast(useCustomSize ? componentProperties.armorBar.bar.placement.customWidth : componentProperties.armorBar.bar.placement.width), static_cast(useCustomSize ? componentProperties.armorBar.bar.placement.customHeight : componentProperties.armorBar.bar.placement.height), playerPed->GetArmor() / static_cast(pGame->GetPlayerInfo()->GetMaxArmor()) * 100.0f, false, componentProperties.armorBar.bar.drawPercentage, componentProperties.armorBar.bar.drawBlackBorder, componentProperties.armorBar.bar.fillColor, COLOR_BLACK); + ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, barWidth, barHeight, playerPed->GetArmor() / static_cast(pGame->GetPlayerInfo()->GetMaxArmor()) * 100.0f, false, componentProperties.armorBar.drawPercentage, componentProperties.armorBar.drawBlackBorder, componentProperties.armorBar.fillColor, COLOR_BLACK); +} + +void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor) +{ + // Use custom position/size? + bool useCustomPosition = properties.placement.useCustomPosition; + bool useCustomSize = properties.placement.useCustomSize; + + // Save default position once + if (!properties.placement.setDefaultXY) + { + properties.placement.x = x; + properties.placement.y = y; + properties.placement.setDefaultXY = true; + } + + CFontSA::SetScale(useCustomSize ? properties.placement.customWidth : properties.placement.width, useCustomSize ? properties.placement.customHeight : properties.placement.height); + CFontSA::SetProportional(properties.proportional); + + CFontSA::SetDropShadowPosition(properties.textShadow); + CFontSA::SetEdge(properties.textOutline); + + //if (properties.textShadow >= 0 && properties.textOutline <= 0) + // CFontSA::SetDropShadowPosition(properties.textShadow); + + CFontSA::SetOrientation(properties.alignment); + CFontSA::SetFontStyle(properties.style); + + CFontSA::SetDropColor(properties.dropColor); + CFontSA::SetColor(useSecondColor ? properties.fillColor_Second : properties.fillColor); + + // Draw text + CFontSA::PrintString(useCustomPosition ? properties.placement.customX : x, useCustomPosition ? properties.placement.customY : y, text); +} + +void CHudSA::RenderClock(float x, float y, const char* strTime) +{ + RenderText(x, y, strTime, componentProperties.clock); +} + +void CHudSA::RenderMoney(float x, float y, const char* strMoney) +{ + RenderText(x, y, strMoney, componentProperties.money, pGame->GetPlayerInfo()->GetPlayerMoney() < 0); } static void _declspec(naked) HOOK_RenderHudBar() @@ -578,4 +731,7 @@ void CHudSA::StaticSetHooks() HookInstall(FUNC_RenderHealthBar, &HOOK_RenderHudBar, 11); HookInstall(FUNC_RenderBreathBar, &HOOK_RenderHudBar, 11); HookInstall(FUNC_RenderArmorBar, &HOOK_RenderHudBar, 11); + + HookInstallCall(0x58EC21, (DWORD)&RenderClock); + HookInstallCall(0x58F607, (DWORD)&RenderMoney); } diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index fd99e64bd3..7841e4dda4 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -14,6 +14,7 @@ #include #include #include +#include "CFontSA.h" #define FUNC_Draw 0x58FAE0 @@ -83,18 +84,18 @@ enum class eHudColour struct RsGlobal { - const char* appName; + const char* appName; std::int32_t maximumWidth; std::int32_t maximumHeight; std::int32_t frameLimit; - bool quit; - void* ps; + bool quit; + void* ps; std::uint8_t keyboard[12]; // RsInputDevice std::uint8_t mouse[12]; // RsInputDevice std::uint8_t pad[12]; // RsInputDevice }; -struct ComponentPlacement +struct SComponentPlacement { // Original position & size float x{0.0f}, y{0.0f}; // for getter function only @@ -109,35 +110,54 @@ struct ComponentPlacement bool setDefaultXY{false}; }; -struct HudBar +struct SHudComponentData { - ComponentPlacement placement; - RwColor fillColor{}; - bool drawBlackBorder{true}; - bool drawPercentage{false}; -}; - -struct HealthBar -{ - HudBar bar; - float blinkingBarHP{10.0f}; -}; - -struct BreathBar -{ - HudBar bar; -}; - -struct ArmorBar -{ - HudBar bar; + SComponentPlacement placement{}; + RwColor fillColor{}; + RwColor fillColor_Second{0,0,0,255}; + + // Bar + bool drawBlackBorder{true}; + bool drawPercentage{false}; + + // Text + RwColor dropColor{}; + eFontAlignment alignment{}; + eFontStyle style{}; + std::int16_t textOutline{0}; + std::int16_t textShadow{0}; + bool proportional{false}; + + SHudComponentData( + RwColor fill = {}, + RwColor fillSecond = {0, 0, 0, 255}, + bool blackBorder = true, + bool percentage = false, + RwColor drop = {}, + eFontAlignment align = eFontAlignment::ALIGN_LEFT, + eFontStyle fontStyle = eFontStyle::FONT_PRICEDOWN, + std::int16_t outline = 0, + std::int16_t shadow = 0, + bool prop = false) : fillColor(fill), + fillColor_Second(fillSecond), + drawBlackBorder(blackBorder), + drawPercentage(percentage), + dropColor(drop), + alignment(align), + style(fontStyle), + textOutline(outline), + textShadow(shadow), + proportional(prop) {} }; struct ComponentProperties { - HealthBar hpBar; - BreathBar breathBar; - ArmorBar armorBar; + SHudComponentData hpBar; + SHudComponentData breathBar; + SHudComponentData armorBar; + + SHudComponentData clock; + SHudComponentData money; }; class CHudSA : public CHud @@ -152,35 +172,59 @@ class CHudSA : public CHud void ResetComponentAdjustment(); bool IsCrosshairVisible(); - void SetComponentPlacementPosition(ComponentPlacement& placement, const CVector2D& position); - void SetComponentPlacementSize(ComponentPlacement& placement, const CVector2D& size); + bool IsComponentBar(const eHudComponent& component) const noexcept override; + bool IsComponentText(const eHudComponent& component) const noexcept override; + + void SetComponentPlacementPosition(SComponentPlacement& placement, const CVector2D& position) noexcept; + void SetComponentPlacementSize(SComponentPlacement& placement, const CVector2D& size) noexcept; void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept override; void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept override; void ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept override; - void SetComponentBarColor(const eHudComponent& component, float color) noexcept override; - void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept override; - void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept override; - void SetHealthBarBlinkingValue(float minHealth) noexcept override; + void SetComponentColor(const eHudComponent& component, std::uint32_t color, bool secondColor = false) noexcept override; + void ResetComponentColor(const eHudComponent& component, bool secondColor = false) noexcept override; + + void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept override { GetHudComponentRef(component).drawBlackBorder = draw; } + void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept override { GetHudComponentRef(component).drawPercentage = draw; } + void SetHealthBarBlinkingValue(float minHealth) noexcept override { blinkingBarHPValue = minHealth; } + + void SetComponentFontDropColor(const eHudComponent& component, std::uint32_t color) noexcept override; + void SetComponentFontOutline(const eHudComponent& component, float outline) noexcept override { GetHudComponentRef(component).textOutline = static_cast(outline); } + void SetComponentFontShadow(const eHudComponent& component, float shadow) noexcept override { GetHudComponentRef(component).textShadow = static_cast(shadow); } + void SetComponentFontStyle(const eHudComponent& component, const eFontStyle& style) noexcept override { GetHudComponentRef(component).style = style; } + void SetComponentFontAlignment(const eHudComponent& component, const eFontAlignment& alignment) noexcept override { GetHudComponentRef(component).alignment = alignment; } + void SetComponentFontProportional(const eHudComponent& component, bool proportional) noexcept override { GetHudComponentRef(component).proportional = proportional; } + + void ResetComponentFontOutline(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_OUTLINE); } + void ResetComponentFontShadow(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_SHADOW); } + void ResetComponentFontStyle(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_STYLE); } + void ResetComponentFontAlignment(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_ALIGNMENT); } + void ResetComponentFontProportional(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_PROPORTIONAL); } static RsGlobal* GetRSGlobal() noexcept { return rsGlobal; } - static RwColor GetHUDColour(const eHudColour& colour); + static RwColor GetHUDColour(const eHudColour& colour) noexcept; static void StaticSetHooks(); -protected: +private: void InitComponentList(); void UpdateStreetchCalculations(); - void ResetComponent(ComponentPlacement& placement, bool resetSize) noexcept; + void ResetComponent(SComponentPlacement& placement, bool resetSize) noexcept; + void ResetComponentFontData(const eHudComponent& component, const eHudComponentProperty& property) noexcept; + + SHudComponentData& GetHudComponentRef(const eHudComponent& component) const noexcept; static void RenderHealthBar(int x, int y); static void RenderBreathBar(int x, int y); static void RenderArmorBar(int x, int y); - static HudBar& GetHudBarRef(const eHudComponent& component) noexcept; + static void RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor = false); + static void RenderClock(float x, float y, const char* strTime); + static void RenderMoney(float x, float y, const char* strMoney); +private: std::map m_HudComponentMap; float* m_pfAspectRatioMultiplicator; @@ -192,4 +236,5 @@ class CHudSA : public CHud static float calcStreetchX; static float calcStreetchY; + static float blinkingBarHPValue; }; diff --git a/Client/game_sa/CPlayerInfoSA.h b/Client/game_sa/CPlayerInfoSA.h index 057c2927ab..108864c5f8 100644 --- a/Client/game_sa/CPlayerInfoSA.h +++ b/Client/game_sa/CPlayerInfoSA.h @@ -268,6 +268,6 @@ class CPlayerInfoSA : public CPlayerInfo float GetBikeRearWheelDist() { return internalInterface->fBikeRearWheelDist; } DWORD GetBikeFrontWheelCounter() { return internalInterface->nBikeFrontWheelCounter; } float GetBikeFrontWheelDist() { return internalInterface->fBikeFrontWheelDist; } - std::uint8_t GetMaxHealth() { return internalInterface->MaxHealth; } - std::uint8_t GetMaxArmor() { return internalInterface->MaxArmour; } + std::uint8_t GetMaxHealth() const { return internalInterface->MaxHealth; } + std::uint8_t GetMaxArmor() const { return internalInterface->MaxArmour; } }; diff --git a/Client/game_sa/HookSystem.cpp b/Client/game_sa/HookSystem.cpp index 794e9dd68c..fda4d315f3 100644 --- a/Client/game_sa/HookSystem.cpp +++ b/Client/game_sa/HookSystem.cpp @@ -18,3 +18,10 @@ BYTE* CreateJump(DWORD dwFrom, DWORD dwTo, BYTE* ByteArray) MemPutFast(&ByteArray[1], dwTo - (dwFrom + 5)); return ByteArray; } + +void HookInstallCall(DWORD dwInstallAddress, DWORD dwHookFunction) +{ + DWORD dwOffset = dwHookFunction - (dwInstallAddress + 5); + MemPut(dwInstallAddress, 0xE8); + MemPut(dwInstallAddress + 1, dwOffset); +} diff --git a/Client/game_sa/HookSystem.h b/Client/game_sa/HookSystem.h index 19f145a2b7..646cfd6c66 100644 --- a/Client/game_sa/HookSystem.h +++ b/Client/game_sa/HookSystem.h @@ -24,6 +24,8 @@ void* FunctionPointerToVoidP(T func) return c.b; } +void HookInstallCall(DWORD dwInstallAddress, DWORD dwHookFunction); + template bool HookInstall(DWORD dwInstallAddress, T dwHookHandler, int iJmpCodeSize = 5) { diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index ace6ec2010..6ef31e4c1f 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -115,11 +115,32 @@ IMPLEMENT_ENUM_CLASS_BEGIN(eHudComponentProperty) ADD_ENUM(eHudComponentProperty::POSITION, "position") ADD_ENUM(eHudComponentProperty::SIZE, "size") ADD_ENUM(eHudComponentProperty::FILL_COLOR, "fillColor") +ADD_ENUM(eHudComponentProperty::FILL_COLOR_SECOND, "fillColor_second") ADD_ENUM(eHudComponentProperty::DRAW_BLACK_BORDER, "drawBlackBorder") ADD_ENUM(eHudComponentProperty::DRAW_PERCENTAGE, "drawPercentage") ADD_ENUM(eHudComponentProperty::BLINKING_HP_VALUE, "blinkingValue") +ADD_ENUM(eHudComponentProperty::DROP_COLOR, "dropColor") +ADD_ENUM(eHudComponentProperty::TEXT_OUTLINE, "fontOutline") +ADD_ENUM(eHudComponentProperty::TEXT_SHADOW, "fontShadow") +ADD_ENUM(eHudComponentProperty::TEXT_STYLE, "fontStyle") +ADD_ENUM(eHudComponentProperty::TEXT_ALIGNMENT, "fontAlignment") +ADD_ENUM(eHudComponentProperty::TEXT_PROPORTIONAL, "proportional") +ADD_ENUM(eHudComponentProperty::ALL_PROPERTIES, "all") IMPLEMENT_ENUM_CLASS_END("hud-component-property") +IMPLEMENT_ENUM_CLASS_BEGIN(eFontStyle) +ADD_ENUM(eFontStyle::FONT_GOTHIC, "gothic") +ADD_ENUM(eFontStyle::FONT_MENU, "menu") +ADD_ENUM(eFontStyle::FONT_PRICEDOWN, "pricedown") +ADD_ENUM(eFontStyle::FONT_SUBTITLES, "subtitles") +IMPLEMENT_ENUM_CLASS_END("hud-component-font-style") + +IMPLEMENT_ENUM_CLASS_BEGIN(eFontAlignment) +ADD_ENUM(eFontAlignment::ALIGN_CENTER, "center") +ADD_ENUM(eFontAlignment::ALIGN_LEFT, "left") +ADD_ENUM(eFontAlignment::ALIGN_RIGHT, "right") +IMPLEMENT_ENUM_CLASS_END("hud-component-font-alignment") + IMPLEMENT_ENUM_BEGIN(eAmbientSoundType) ADD_ENUM(AMBIENT_SOUND_GENERAL, "general") ADD_ENUM(AMBIENT_SOUND_GUNFIRE, "gunfire") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index fffe9810b5..9a8ae6d7cd 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -109,6 +109,8 @@ DECLARE_ENUM(eDXVerticalAlign); DECLARE_ENUM(eHudComponent); DECLARE_ENUM_CLASS(eHudComponentProperty); +DECLARE_ENUM_CLASS(eFontStyle); +DECLARE_ENUM_CLASS(eFontAlignment); enum eFieldOfViewMode { diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index 4b4247c9f3..fdf56a6372 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp @@ -649,8 +649,10 @@ bool CLuaPlayerDefs::IsPlayerCrosshairVisible() return g_pGame->GetHud()->IsCrosshairVisible(); } -bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value) +bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value) { + CHud* hud = g_pGame->GetHud(); + switch (property) { case eHudComponentProperty::POSITION: @@ -658,7 +660,7 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!std::holds_alternative(value)) return false; - g_pGame->GetHud()->SetComponentPosition(component, std::get(value)); + hud->SetComponentPosition(component, std::get(value)); return true; } case eHudComponentProperty::SIZE: @@ -666,62 +668,42 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!std::holds_alternative(value)) return false; - g_pGame->GetHud()->SetComponentSize(component, std::get(value)); + hud->SetComponentSize(component, std::get(value)); return true; } case eHudComponentProperty::FILL_COLOR: + case eHudComponentProperty::FILL_COLOR_SECOND: { - switch (component) - { - case HUD_HEALTH: - case HUD_ARMOUR: - case HUD_BREATH: - { - if (!std::holds_alternative(value)) - return false; + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component)) + return false; - g_pGame->GetHud()->SetComponentBarColor(component, std::get(value)); - return true; - } - } + if (!std::holds_alternative(value)) + return false; - break; + hud->SetComponentColor(component, static_cast(std::get(value)), property == eHudComponentProperty::FILL_COLOR_SECOND); + return true; } case eHudComponentProperty::DRAW_BLACK_BORDER: { - switch (component) - { - case HUD_HEALTH: - case HUD_ARMOUR: - case HUD_BREATH: - { - if (!std::holds_alternative(value)) - return false; + if (!hud->IsComponentBar(component)) + return false; - g_pGame->GetHud()->SetComponentDrawBlackBorder(component, std::get(value)); - return true; - } - } + if (!std::holds_alternative(value)) + return false; - break; + hud->SetComponentDrawBlackBorder(component, std::get(value)); + return true; } case eHudComponentProperty::DRAW_PERCENTAGE: { - switch (component) - { - case HUD_HEALTH: - case HUD_ARMOUR: - case HUD_BREATH: - { - if (!std::holds_alternative(value)) - return false; + if (!hud->IsComponentBar(component)) + return false; - g_pGame->GetHud()->SetComponentDrawPercentage(component, std::get(value)); - return true; - } - } + if (!std::holds_alternative(value)) + return false; - break; + hud->SetComponentDrawPercentage(component, std::get(value)); + return true; } case eHudComponentProperty::BLINKING_HP_VALUE: { @@ -731,7 +713,81 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!std::holds_alternative(value)) return false; - g_pGame->GetHud()->SetHealthBarBlinkingValue(std::get(value)); + hud->SetHealthBarBlinkingValue(std::get(value)); + return true; + } + case eHudComponentProperty::DROP_COLOR: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentFontDropColor(component, static_cast(std::get(value))); + return true; + } + case eHudComponentProperty::TEXT_OUTLINE: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentFontOutline(component, std::get(value)); + return true; + } + case eHudComponentProperty::TEXT_SHADOW: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentFontShadow(component, std::get(value)); + return true; + } + case eHudComponentProperty::TEXT_STYLE: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + eFontStyle val = std::get(value); + if (val < eFontStyle::FONT_GOTHIC || val > eFontStyle::FONT_PRICEDOWN) + return false; + + hud->SetComponentFontStyle(component, val); + return true; + } + case eHudComponentProperty::TEXT_ALIGNMENT: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + eFontAlignment val = std::get(value); + if (val < eFontAlignment::ALIGN_CENTER || val > eFontAlignment::ALIGN_RIGHT) + return false; + + hud->SetComponentFontAlignment(component, val); + return true; + } + case eHudComponentProperty::TEXT_PROPORTIONAL: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentFontProportional(component, std::get(value)); return true; } } @@ -741,75 +797,105 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) { + CHud* hud = g_pGame->GetHud(); + switch (property) { - case eHudComponentProperty::POSITION: + case eHudComponentProperty::ALL_PROPERTIES: { - g_pGame->GetHud()->ResetComponentPlacement(component, false); + for (int i = 0; i < static_cast(eHudComponentProperty::ALL_PROPERTIES); i++) + ResetPlayerHudComponentProperty(component, static_cast(i)); + return true; } + case eHudComponentProperty::POSITION: + hud->ResetComponentPlacement(component, false); + return true; case eHudComponentProperty::SIZE: + hud->ResetComponentPlacement(component, true); + return true; + case eHudComponentProperty::FILL_COLOR: + case eHudComponentProperty::FILL_COLOR_SECOND: { - g_pGame->GetHud()->ResetComponentPlacement(component, true); + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component)) + return false; + + hud->ResetComponentColor(component, property == eHudComponentProperty::FILL_COLOR_SECOND); return true; } - case eHudComponentProperty::FILL_COLOR: + case eHudComponentProperty::DROP_COLOR: { - switch (component) - { - case HUD_HEALTH: - // eHudColour::RED - g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(180, 25, 29, 255)); - return true; - case HUD_BREATH: - // eHudColour::LIGHT_BLUE - g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(172, 203, 241, 255)); - return true; - case HUD_ARMOUR: - // eHudColour::LIGHT_GRAY - g_pGame->GetHud()->SetComponentBarColor(component, COLOR_RGBA(225, 225, 225, 255)); - return true; - } + if (!hud->IsComponentText(component)) + return false; - break; + hud->SetComponentFontDropColor(component, COLOR_RGBA(0, 0, 0, 255)); + return true; } case eHudComponentProperty::DRAW_BLACK_BORDER: { - switch (component) - { - case HUD_HEALTH: - case HUD_BREATH: - case HUD_ARMOUR: - g_pGame->GetHud()->SetComponentDrawBlackBorder(component, true); - return true; - } + if (!hud->IsComponentBar(component)) + return false; - break; + hud->SetComponentDrawBlackBorder(component, true); + return true; } case eHudComponentProperty::DRAW_PERCENTAGE: { - switch (component) - { - case HUD_HEALTH: - case HUD_BREATH: - case HUD_ARMOUR: - g_pGame->GetHud()->SetComponentDrawPercentage(component, false); - return true; - } + if (!hud->IsComponentBar(component)) + return false; - break; + hud->SetComponentDrawPercentage(component, false); + return true; } case eHudComponentProperty::BLINKING_HP_VALUE: { - if (component == HUD_HEALTH) - { - g_pGame->GetHud()->SetHealthBarBlinkingValue(10.0f); - return true; - } + if (!component != HUD_HEALTH) + return false; + + hud->SetHealthBarBlinkingValue(10.0f); + return true; + } + case eHudComponentProperty::TEXT_OUTLINE: + { + if (!hud->IsComponentText(component)) + return false; + + hud->ResetComponentFontOutline(component); + return true; + } + case eHudComponentProperty::TEXT_SHADOW: + { + if (!hud->IsComponentText(component)) + return false; - break; + hud->ResetComponentFontShadow(component); + return true; + } + case eHudComponentProperty::TEXT_STYLE: + { + if (!hud->IsComponentText(component)) + return false; + + hud->ResetComponentFontStyle(component); + return true; + } + case eHudComponentProperty::TEXT_ALIGNMENT: + { + if (!hud->IsComponentText(component)) + return false; + + hud->ResetComponentFontAlignment(component); + return true; + } + case eHudComponentProperty::TEXT_PROPORTIONAL: + { + if (!hud->IsComponentText(component)) + return false; + + hud->ResetComponentFontProportional(component); + return true; } } return false; -} +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h index 8baca7900c..34fe6c7c4d 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h @@ -41,7 +41,7 @@ class CLuaPlayerDefs : public CLuaDefs LUA_DECLARE(SetPlayerNametagText); LUA_DECLARE(SetPlayerNametagColor); LUA_DECLARE(SetPlayerNametagShowing); - static bool SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value); + static bool SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value); static bool ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property); // Community funcs diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index 837a2ce034..1259ede7dd 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -156,7 +156,7 @@ class __declspec(novtable) CGame virtual CModelInfo* GetModelInfo(DWORD dwModelID, bool bCanBeInvalid = false) = 0; virtual DWORD GetSystemTime() = 0; - virtual int GetSystemFrameCounter() = 0; + virtual int GetSystemFrameCounter() const = 0; virtual bool IsAtMenu() = 0; virtual void StartGame() = 0; virtual void SetSystemState(eSystemState State) = 0; diff --git a/Client/sdk/game/CHud.h b/Client/sdk/game/CHud.h index 208a6e8a37..e6a3594b7f 100644 --- a/Client/sdk/game/CHud.h +++ b/Client/sdk/game/CHud.h @@ -36,11 +36,35 @@ enum eHudComponent enum class eHudComponentProperty { FILL_COLOR, + FILL_COLOR_SECOND, DRAW_BLACK_BORDER, DRAW_PERCENTAGE, BLINKING_HP_VALUE, POSITION, SIZE, + DROP_COLOR, + TEXT_OUTLINE, + TEXT_SHADOW, + TEXT_STYLE, + TEXT_ALIGNMENT, + TEXT_PROPORTIONAL, + + ALL_PROPERTIES, +}; + +enum class eFontStyle +{ + FONT_GOTHIC = 0, + FONT_SUBTITLES, + FONT_MENU, + FONT_PRICEDOWN, +}; + +enum class eFontAlignment +{ + ALIGN_CENTER, + ALIGN_LEFT, + ALIGN_RIGHT, }; class CHud @@ -55,11 +79,30 @@ class CHud virtual bool IsCrosshairVisible() = 0; // Hud properties - virtual void SetComponentBarColor(const eHudComponent& component, float color) noexcept = 0; - virtual void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept = 0; - virtual void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept = 0; - virtual void SetHealthBarBlinkingValue(float minHealth) noexcept = 0; + virtual bool IsComponentBar(const eHudComponent& component) const noexcept = 0; + virtual bool IsComponentText(const eHudComponent& component) const noexcept = 0; + virtual void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept = 0; virtual void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept = 0; virtual void ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept = 0; + + virtual void SetComponentColor(const eHudComponent& component, std::uint32_t color, bool secondColor = false) noexcept = 0; + virtual void ResetComponentColor(const eHudComponent& component, bool secondColor = false) noexcept = 0; + + virtual void SetComponentDrawBlackBorder(const eHudComponent& component, bool draw) noexcept = 0; + virtual void SetComponentDrawPercentage(const eHudComponent& component, bool draw) noexcept = 0; + virtual void SetHealthBarBlinkingValue(float minHealth) noexcept = 0; + + virtual void SetComponentFontDropColor(const eHudComponent& component, std::uint32_t color) noexcept = 0; + virtual void SetComponentFontOutline(const eHudComponent& component, float outline) noexcept = 0; + virtual void SetComponentFontShadow(const eHudComponent& component, float shadow) noexcept = 0; + virtual void SetComponentFontStyle(const eHudComponent& component, const eFontStyle& style) noexcept = 0; + virtual void SetComponentFontAlignment(const eHudComponent& component, const eFontAlignment& alignment) noexcept = 0; + virtual void SetComponentFontProportional(const eHudComponent& component, bool proportional) noexcept = 0; + + virtual void ResetComponentFontOutline(const eHudComponent& component) noexcept = 0; + virtual void ResetComponentFontShadow(const eHudComponent& component) noexcept = 0; + virtual void ResetComponentFontStyle(const eHudComponent& component) noexcept = 0; + virtual void ResetComponentFontAlignment(const eHudComponent& component) noexcept = 0; + virtual void ResetComponentFontProportional(const eHudComponent& component) noexcept = 0; }; diff --git a/Client/sdk/game/CPlayerInfo.h b/Client/sdk/game/CPlayerInfo.h index 44f0e08787..93a87c4c9e 100644 --- a/Client/sdk/game/CPlayerInfo.h +++ b/Client/sdk/game/CPlayerInfo.h @@ -38,6 +38,6 @@ class CPlayerInfo virtual float GetBikeRearWheelDist() = 0; virtual DWORD GetBikeFrontWheelCounter() = 0; virtual float GetBikeFrontWheelDist() = 0; - virtual std::uint8_t GetMaxHealth() = 0; - virtual std::uint8_t GetMaxArmor() = 0; + virtual std::uint8_t GetMaxHealth() const = 0; + virtual std::uint8_t GetMaxArmor() const = 0; }; From e38e5c62facbc93f2958da90677ea3fc658a6733 Mon Sep 17 00:00:00 2001 From: FileEX Date: Fri, 27 Dec 2024 00:12:06 +0100 Subject: [PATCH 3/5] Final update --- Client/game_sa/CAERadioTrackManagerSA.cpp | 6 + Client/game_sa/CAERadioTrackManagerSA.h | 87 +++++ Client/game_sa/CFontSA.cpp | 13 +- Client/game_sa/CFontSA.h | 10 +- Client/game_sa/CHudSA.cpp | 365 ++++++++++++++---- Client/game_sa/CHudSA.h | 55 ++- Client/mods/deathmatch/logic/CClientGame.cpp | 3 + .../logic/lua/CLuaFunctionParseHelpers.cpp | 1 + .../logic/luadefs/CLuaPlayerDefs.cpp | 173 ++++++++- .../deathmatch/logic/luadefs/CLuaPlayerDefs.h | 5 +- Client/sdk/game/CAERadioTrackManager.h | 1 + Client/sdk/game/CHud.h | 28 +- 12 files changed, 654 insertions(+), 93 deletions(-) diff --git a/Client/game_sa/CAERadioTrackManagerSA.cpp b/Client/game_sa/CAERadioTrackManagerSA.cpp index 87e865d958..80586215d2 100644 --- a/Client/game_sa/CAERadioTrackManagerSA.cpp +++ b/Client/game_sa/CAERadioTrackManagerSA.cpp @@ -107,3 +107,9 @@ void CAERadioTrackManagerSA::StartRadio(BYTE bStationID, BYTE bUnknown) call dwFunc } } + +bool CAERadioTrackManagerSA::IsStationLoading() const +{ + CAERadioTrackManagerSAInterface* trackInterface = GetInterface(); + return (trackInterface->stationsListed || trackInterface->stationsListDown); +} diff --git a/Client/game_sa/CAERadioTrackManagerSA.h b/Client/game_sa/CAERadioTrackManagerSA.h index 891730a798..f0b8f34140 100644 --- a/Client/game_sa/CAERadioTrackManagerSA.h +++ b/Client/game_sa/CAERadioTrackManagerSA.h @@ -23,9 +23,95 @@ #define CLASS_CAERadioTrackManager 0x8CB6F8 +enum class eRadioTrackMode +{ + RADIO_STARTING, + RADIO_WAITING_TO_PLAY, + RADIO_PLAYING, + RADIO_STOPPING, + RADIO_STOPPING_SILENCED, + RADIO_STOPPING_CHANNELS_STOPPED, + RADIO_WAITING_TO_STOP, + RADIO_STOPPED +}; + +struct tRadioSettings +{ + std::int32_t djIndex[4]; + std::int32_t currentTrackId; + std::int32_t prevTrackId; + std::int32_t trackPlayTime; + std::int32_t trackLengthInMS; + std::uint8_t trackFlags[2]; + std::uint8_t currentRadioStation; + std::uint8_t field_27; + std::uint8_t bassSet; + float bassGain; + std::uint8_t trackTypes[4]; + std::uint8_t currentTrackType; + std::uint8_t prevTrackType; + std::int8_t trackIndexes[10]; +}; +static_assert(sizeof(tRadioSettings) == 0x3C, "Invalid size of tRadioSettings struct!"); + +struct tRadioState +{ + std::int32_t elapsed[3]; + std::int32_t timeInPauseModeInMS; + std::int32_t timeInMS; + std::int32_t trackPlayTime; + std::int32_t trackQueue[3]; + std::uint8_t trackTypes[3]; + std::uint8_t gameMonthDay; + std::uint8_t gameClockHours; +}; +static_assert(sizeof(tRadioState) == 0x2C, "Invalid size of tRadioState struct!"); + +class CAERadioTrackManagerSAInterface +{ +public: + bool isInitialised; + bool displayStationName; + std::uint8_t field_2; + bool enableInPauseMode; + bool bassEnhance; + bool pauseMode; + bool retuneJustStarted; + bool autoSelect; + std::uint8_t tracksInARow[14]; + std::uint8_t gameMonthDay; + std::uint8_t gameClockHours; + std::int32_t listenItems[14]; + std::uint32_t timeRadioStationReturned; + std::uint32_t timeToDisplayRadioName; + std::uint32_t savedTimeInMS; + std::uint32_t retuneStartedTime; + std::uint8_t field_60[4]; + std::int32_t hwClientHandle; + eRadioTrackMode trackMode; + std::int32_t stationsListed; + std::int32_t stationsListDown; + std::int32_t savedRadioStationId; + std::int32_t radioStationMenuRequest; + std::int32_t radioStationScriptRequest; + float volume1; + float volume2; + tRadioSettings requestedSettings; + tRadioSettings activeSettings; + tRadioState radioState[13]; + std::uint8_t field_33C[12]; + std::uint8_t field_348[32]; + std::uint32_t field_368; + std::uint8_t userTrackPlayMode; + std::uint8_t field_36D[3]; +}; +static_assert(sizeof(CAERadioTrackManagerSAInterface) == 0x370, "Invalid size of CAERadioTrackManagerSAInterface class!"); + class CAERadioTrackManagerSA : public CAERadioTrackManager { public: + CAERadioTrackManagerSAInterface* GetInterface() const noexcept { return reinterpret_cast(CLASS_CAERadioTrackManager); } + BYTE GetCurrentRadioStationID(); BYTE IsVehicleRadioActive(); char* GetRadioStationName(BYTE bStationID); @@ -33,4 +119,5 @@ class CAERadioTrackManagerSA : public CAERadioTrackManager void SetBassSetting(DWORD dwBass); void Reset(); void StartRadio(BYTE bStationID, BYTE bUnknown); + bool IsStationLoading() const; }; diff --git a/Client/game_sa/CFontSA.cpp b/Client/game_sa/CFontSA.cpp index 4ff40aeb54..bf17b8a1dd 100644 --- a/Client/game_sa/CFontSA.cpp +++ b/Client/game_sa/CFontSA.cpp @@ -41,6 +41,12 @@ void CFontSA::SetScale(const CVector2D& scale) SetScale(scale.fX, scale.fY); } +void CFontSA::SetScaleForCurrentLanguage(float w, float h) +{ + // Call CFont::SetScaleForCurrentLanguage + ((void(__cdecl*)(float, float))FUNC_CFont_SetScaleForCurrentLanguage)(w, h); +} + void CFontSA::SetSlantRefPoint(float x, float y) { // Call CFont::SetSlantRefPoint @@ -68,7 +74,7 @@ void CFontSA::SetDropColor(const RwColor& color) void CFontSA::SetFontStyle(const eFontStyle& style) { // Call CFont::SetFontStyle - ((void(__cdecl*)(std::uint16_t))FUNC_CFont_SetStyle)(static_cast(style)); + ((void(__cdecl*)(eFontStyle))FUNC_CFont_SetStyle)(style); } void CFontSA::SetWrapX(float wrapx) @@ -143,6 +149,11 @@ std::int16_t CFontSA::GetNumberLines(float x, float y, const char* text) return ((std::int16_t(__cdecl*)(float, float, const char*))FUNC_CFont_GetNumberLines)(x, y, text); } +float CFontSA::GetFontHeight(float scaleY) +{ + return scaleY * 16.0f + scaleY * 2.0f; +} + eFontAlignment CFontSA::GetOrientation() { bool centerAlign = *reinterpret_cast(VAR_CFont_CenterAlign); diff --git a/Client/game_sa/CFontSA.h b/Client/game_sa/CFontSA.h index c2da521bd3..6c5b0a5cdd 100644 --- a/Client/game_sa/CFontSA.h +++ b/Client/game_sa/CFontSA.h @@ -19,6 +19,7 @@ #define FUNC_CFont_PrintStringFromBottom 0x71A820 #define FUNC_CFont_SetScale 0x719380 +#define FUNC_CFont_SetScaleForCurrentLanguage 0x7193A0 #define FUNC_CFont_SetSlantRefPoint 0x719400 #define FUNC_CFont_SetSlant 0x719420 @@ -82,6 +83,7 @@ class CFontSA static void SetScale(float w, float h); static void SetScale(const CVector2D& scale); + static void SetScaleForCurrentLanguage(float w, float h); static void SetSlantRefPoint(float x, float y); static void SetSlant(float slant); @@ -108,9 +110,11 @@ class CFontSA static float GetStringWidth(const char* string, bool spaces, bool scriptValues = false); static std::int16_t GetNumberLines(float x, float y, const char* text); + static float GetFontHeight(float scaleY); static CVector2D GetScale() { return *reinterpret_cast(VAR_CFont_Scale); } static RwColor GetColor() { return *reinterpret_cast(VAR_CFont_Color); } + static RwColor GetDropColor() { return *reinterpret_cast(VAR_CFont_DropColor); } static float GetSlant() { return *reinterpret_cast(VAR_CFont_Slant); } static CVector2D GetSlantRefPoint() { return *reinterpret_cast(VAR_CFont_SlantRefPoint); } @@ -130,6 +134,8 @@ class CFontSA static eFontStyle GetFontStyle(); - static float GetEdge() { return *reinterpret_cast(VAR_CFont_Edge); } - static float GetDropdownShadow() { return *reinterpret_cast(VAR_CFont_Shadow); } + static float GetEdge() { return static_cast(*reinterpret_cast(VAR_CFont_Edge)); } + static float GetDropdownShadow() { return static_cast(*reinterpret_cast(VAR_CFont_Shadow)); } + + static bool GetProportional() { return *reinterpret_cast(VAR_CFont_Proportional); } }; diff --git a/Client/game_sa/CHudSA.cpp b/Client/game_sa/CHudSA.cpp index cc0eec2b26..b30eb03589 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -15,6 +15,7 @@ #include "CCameraSA.h" #include "CPlayerInfoSA.h" #include "TaskAttackSA.h" +#include "CAERadioTrackManagerSA.h" extern CGameSA* pGame; @@ -32,12 +33,22 @@ float CHudSA::blinkingBarHPValue = 10.0f; constexpr RwColor COLOR_BLACK = RwColor{0, 0, 0, 255}; +// CSprite2d::DrawBarChart +using DrawBarChartFunc = void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor); +DrawBarChartFunc DrawBarChart = reinterpret_cast(FUNC_CSprite2d_DrawBarChart); + // default component properties std::unordered_map defaultComponentProperties = { {HUD_HEALTH, {CHudSA::GetHUDColour(eHudColour::RED)}}, {HUD_BREATH, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE)}}, {HUD_CLOCK, {CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}}, - {HUD_MONEY, {CHudSA::GetHUDColour(eHudColour::GREEN), CHudSA::GetHUDColour(eHudColour::RED), false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}} + {HUD_MONEY, {CHudSA::GetHUDColour(eHudColour::GREEN), CHudSA::GetHUDColour(eHudColour::RED), false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}}, + {HUD_AMMO, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_CENTER, eFontStyle::FONT_SUBTITLES, 1, 0, true}}, + {HUD_VEHICLE_NAME, {CHudSA::GetHUDColour(eHudColour::GREEN), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_CENTER, eFontStyle::FONT_MENU, 2, 0, true}}, + {HUD_AREA_NAME, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_CENTER, eFontStyle::FONT_GOTHIC, 2, 0, true}}, + {HUD_RADIO, {CHudSA::GetHUDColour(eHudColour::GOLD), CHudSA::GetHUDColour(eHudColour::DARK_GRAY), false, false, COLOR_BLACK, eFontAlignment::ALIGN_CENTER, eFontStyle::FONT_MENU, 1, 0, true}}, + {HUD_WEAPON, {RwColor{255, 255, 255, 255}, RwColor{255, 255, 255, 255}}}, + {HUD_WANTED, {CHudSA::GetHUDColour(eHudColour::GOLD), RwColor{0, 0, 0, 170}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_GOTHIC, 1, 0, true}} }; CHudSA::CHudSA() @@ -68,6 +79,12 @@ CHudSA::CHudSA() componentProperties.armorBar = MapGet(defaultComponentProperties, HUD_ARMOUR); componentProperties.clock = MapGet(defaultComponentProperties, HUD_CLOCK); componentProperties.money = MapGet(defaultComponentProperties, HUD_MONEY); + componentProperties.ammo = MapGet(defaultComponentProperties, HUD_AMMO); + componentProperties.vehName = MapGet(defaultComponentProperties, HUD_VEHICLE_NAME); + componentProperties.areaName = MapGet(defaultComponentProperties, HUD_AREA_NAME); + componentProperties.radioName = MapGet(defaultComponentProperties, HUD_RADIO); + componentProperties.weaponIcon = MapGet(defaultComponentProperties, HUD_WEAPON); + componentProperties.wanted = MapGet(defaultComponentProperties, HUD_WANTED); } void CHudSA::Disable(bool bDisabled) @@ -207,6 +224,36 @@ void CHudSA::UpdateStreetchCalculations() moneyPlacement.height = calcStreetchY * 1.1f; moneyPlacement.width = calcStreetchX * 0.55f; moneyPlacement.setDefaultXY = false; + + SComponentPlacement& ammoPlacement = componentProperties.ammo.placement; + ammoPlacement.height = calcStreetchY * 0.7f; + ammoPlacement.width = calcStreetchX * 0.3f; + ammoPlacement.setDefaultXY = false; + + SComponentPlacement& vehNamePlacement = componentProperties.vehName.placement; + vehNamePlacement.height = calcStreetchY * 1.5f; + vehNamePlacement.width = calcStreetchX * 1.0f; + vehNamePlacement.setDefaultXY = false; + + SComponentPlacement& areaNamePlacement = componentProperties.areaName.placement; + areaNamePlacement.height = calcStreetchY * 1.9f; + areaNamePlacement.width = calcStreetchX * 1.2f; + areaNamePlacement.setDefaultXY = false; + + SComponentPlacement& radioPlacement = componentProperties.radioName.placement; + radioPlacement.height = calcStreetchY * 0.9f; + radioPlacement.width = calcStreetchX * 0.6f; + radioPlacement.setDefaultXY = false; + + SComponentPlacement& weaponPlacement = componentProperties.weaponIcon.placement; + weaponPlacement.height = calcStreetchY * 58.0f; + weaponPlacement.width = calcStreetchX * 47.0f; + weaponPlacement.setDefaultXY = false; + + SComponentPlacement& wantedPlacement = componentProperties.wanted.placement; + wantedPlacement.height = calcStreetchY * 1.21f; + wantedPlacement.width = calcStreetchX * 0.6f; + wantedPlacement.setDefaultXY = false; } // @@ -315,6 +362,7 @@ bool CHudSA::IsComponentText(const eHudComponent& component) const noexcept case HUD_AREA_NAME: case HUD_VEHICLE_NAME: case HUD_RADIO: + case HUD_WANTED: return true; } @@ -374,38 +422,6 @@ void CHudSA::SetComponentPlacementSize(SComponentPlacement& placement, const CVe placement.useCustomSize = true; } -void CHudSA::SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept -{ - switch (component) - { - case HUD_BREATH: - SetComponentPlacementPosition(componentProperties.breathBar.placement, position); - break; - case HUD_HEALTH: - SetComponentPlacementPosition(componentProperties.hpBar.placement, position); - break; - case HUD_ARMOUR: - SetComponentPlacementPosition(componentProperties.armorBar.placement, position); - break; - } -} - -void CHudSA::SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept -{ - switch (component) - { - case HUD_BREATH: - SetComponentPlacementSize(componentProperties.breathBar.placement, size); - break; - case HUD_HEALTH: - SetComponentPlacementSize(componentProperties.hpBar.placement, size); - break; - case HUD_ARMOUR: - SetComponentPlacementSize(componentProperties.armorBar.placement, size); - break; - } -} - void CHudSA::ResetComponent(SComponentPlacement& placement, bool resetSize) noexcept { if (resetSize) @@ -424,6 +440,19 @@ void CHudSA::ResetComponent(SComponentPlacement& placement, bool resetSize) noex void CHudSA::ResetComponentFontData(const eHudComponent& component, const eHudComponentProperty& property) noexcept { + if (component == HUD_ALL) + { + for (const auto& cmp : m_HudComponentMap) + { + if (cmp.first == HUD_ALL) + continue; + + ResetComponentFontData(cmp.first, property); + } + + return; + } + if (!IsComponentText(component)) return; @@ -467,45 +496,48 @@ SHudComponentData& CHudSA::GetHudComponentRef(const eHudComponent& component) co return componentProperties.clock; case HUD_MONEY: return componentProperties.money; + case HUD_AMMO: + return componentProperties.ammo; + case HUD_VEHICLE_NAME: + return componentProperties.vehName; + case HUD_AREA_NAME: + return componentProperties.areaName; + case HUD_RADIO: + return componentProperties.radioName; + case HUD_WEAPON: + return componentProperties.weaponIcon; + case HUD_WANTED: + return componentProperties.wanted; } } void CHudSA::ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept { - switch (component) + if (component == HUD_ALL) { - case HUD_ALL: + for (const auto& cmp : m_HudComponentMap) { - for (const auto& cmp : m_HudComponentMap) - { - if (cmp.first == HUD_ALL) - continue; + if (cmp.first == HUD_ALL) + continue; - ResetComponentPlacement(cmp.first, resetSize); - } - - break; + ResetComponentPlacement(cmp.first, resetSize); } - case HUD_HEALTH: - ResetComponent(componentProperties.hpBar.placement, resetSize); - break; - case HUD_BREATH: - ResetComponent(componentProperties.breathBar.placement, resetSize); - break; - case HUD_ARMOUR: - ResetComponent(componentProperties.armorBar.placement, resetSize); - break; + + return; } + + ResetComponent(GetHudComponentRef(component).placement, resetSize); } void CHudSA::SetComponentColor(const eHudComponent& component, std::uint32_t color, bool secondColor) noexcept { SColor newColor = TOCOLOR2SCOLOR(color); + auto& compRef = GetHudComponentRef(component); if (!secondColor) - GetHudComponentRef(component).fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; + compRef.fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; else - GetHudComponentRef(component).fillColor_Second = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; + compRef.fillColor_Second = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; } void CHudSA::ResetComponentColor(const eHudComponent& component, bool secondColor) noexcept @@ -528,6 +560,45 @@ void CHudSA::SetComponentFontDropColor(const eHudComponent& component, std::uint GetHudComponentRef(component).dropColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; } +CVector2D CHudSA::GetComponentPosition(const eHudComponent& component) const noexcept +{ + const auto& ref = GetHudComponentRef(component); + + float x = ref.placement.useCustomPosition ? ref.placement.customX : ref.placement.x; + float y = ref.placement.useCustomPosition ? ref.placement.customY : ref.placement.y; + + return CVector2D(x, y); +} + +CVector2D CHudSA::GetComponentSize(const eHudComponent& component) const noexcept +{ + const auto& ref = GetHudComponentRef(component); + + float w = ref.placement.useCustomSize ? ref.placement.customWidth : ref.placement.width; + float h = ref.placement.useCustomSize ? ref.placement.customHeight : ref.placement.height; + + return CVector2D(w, h); +} + +SColor CHudSA::GetComponentColor(const eHudComponent& component) const noexcept +{ + const auto& ref = GetHudComponentRef(component); + return SColorRGBA(ref.fillColor.r, ref.fillColor.g, ref.fillColor.b, ref.fillColor.a); +} + +SColor CHudSA::GetComponentSecondColor(const eHudComponent& component) const noexcept +{ + const auto& ref = GetHudComponentRef(component); + return SColorRGBA(ref.fillColor_Second.r, ref.fillColor_Second.g, ref.fillColor_Second.b, ref.fillColor_Second.a); +} + +SColor CHudSA::GetComponentFontDropColor(const eHudComponent& component) const +{ + const auto& ref = GetHudComponentRef(component); + const RwColor& color = CFontSA::GetDropColor(); + return SColorRGBA(color.r, color.g, color.b, color.a); +} + void CHudSA::RenderHealthBar(int x, int y) { // Flash each 8 frames @@ -565,7 +636,7 @@ void CHudSA::RenderHealthBar(int x, int y) std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.hpBar.placement.customHeight : componentProperties.hpBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, static_cast(totalWidth), barHeight, playerPed->GetHealth() * 100.0f / maxHealth, false, componentProperties.hpBar.drawPercentage, componentProperties.hpBar.drawBlackBorder, componentProperties.hpBar.fillColor, COLOR_BLACK); + DrawBarChart(posX, posY, static_cast(totalWidth), barHeight, playerPed->GetHealth() * 100.0f / maxHealth, false, componentProperties.hpBar.drawPercentage, componentProperties.hpBar.drawBlackBorder, componentProperties.hpBar.fillColor, COLOR_BLACK); } void CHudSA::RenderBreathBar(int x, int y) @@ -599,7 +670,7 @@ void CHudSA::RenderBreathBar(int x, int y) std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.breathBar.placement.customHeight : componentProperties.breathBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, barWidth, barHeight, playerPed->GetOxygenLevel() / statModifier * 100.0f, false, componentProperties.breathBar.drawPercentage, componentProperties.breathBar.drawBlackBorder, componentProperties.breathBar.fillColor, COLOR_BLACK); + DrawBarChart(posX, posY, barWidth, barHeight, playerPed->GetOxygenLevel() / statModifier * 100.0f, false, componentProperties.breathBar.drawPercentage, componentProperties.breathBar.drawBlackBorder, componentProperties.breathBar.fillColor, COLOR_BLACK); } void CHudSA::RenderArmorBar(int x, int y) @@ -630,10 +701,10 @@ void CHudSA::RenderArmorBar(int x, int y) std::uint32_t barHeight = static_cast(useCustomSize ? componentProperties.armorBar.placement.customHeight : componentProperties.armorBar.placement.height); // call CSprite2d::DrawBarChart - ((void(__cdecl*)(float, float, std::uint16_t, std::uint32_t, float, bool, bool, bool, RwColor, RwColor))FUNC_CSprite2d_DrawBarChart)(posX, posY, barWidth, barHeight, playerPed->GetArmor() / static_cast(pGame->GetPlayerInfo()->GetMaxArmor()) * 100.0f, false, componentProperties.armorBar.drawPercentage, componentProperties.armorBar.drawBlackBorder, componentProperties.armorBar.fillColor, COLOR_BLACK); + DrawBarChart(posX, posY, barWidth, barHeight, playerPed->GetArmor() / static_cast(pGame->GetPlayerInfo()->GetMaxArmor()) * 100.0f, false, componentProperties.armorBar.drawPercentage, componentProperties.armorBar.drawBlackBorder, componentProperties.armorBar.fillColor, COLOR_BLACK); } -void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor) +void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor, bool drawFromBottom, bool scaleForLanguage) { // Use custom position/size? bool useCustomPosition = properties.placement.useCustomPosition; @@ -647,23 +718,47 @@ void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& p properties.placement.setDefaultXY = true; } - CFontSA::SetScale(useCustomSize ? properties.placement.customWidth : properties.placement.width, useCustomSize ? properties.placement.customHeight : properties.placement.height); + float scaleX = useCustomSize ? properties.placement.customWidth : properties.placement.width; + float scaleY = useCustomSize ? properties.placement.customHeight : properties.placement.height; + + if (!scaleForLanguage) + CFontSA::SetScale(scaleX, scaleY); + else + CFontSA::SetScaleForCurrentLanguage(scaleX, scaleY); + CFontSA::SetProportional(properties.proportional); CFontSA::SetDropShadowPosition(properties.textShadow); CFontSA::SetEdge(properties.textOutline); - //if (properties.textShadow >= 0 && properties.textOutline <= 0) - // CFontSA::SetDropShadowPosition(properties.textShadow); - CFontSA::SetOrientation(properties.alignment); CFontSA::SetFontStyle(properties.style); - CFontSA::SetDropColor(properties.dropColor); - CFontSA::SetColor(useSecondColor ? properties.fillColor_Second : properties.fillColor); + if (useSecondColor && &properties == &componentProperties.wanted) + { + CFontSA::SetScale(scaleX * 1.2f, scaleY * 1.2f); + CFontSA::SetEdge(0); + } + + if (!properties.useCustomAlpha) + { + CFontSA::SetDropColor(RwColor{properties.dropColor.r, properties.dropColor.g, properties.dropColor.b, CFontSA::GetColor().a}); + CFontSA::SetColor(useSecondColor ? RwColor{properties.fillColor_Second.r, properties.fillColor_Second.g, properties.fillColor_Second.b, CFontSA::GetColor().a} : RwColor{properties.fillColor.r, properties.fillColor.g, properties.fillColor.b, CFontSA::GetColor().a}); + } + else + { + CFontSA::SetDropColor(properties.dropColor); + CFontSA::SetColor(useSecondColor ? properties.fillColor_Second : properties.fillColor); + } // Draw text - CFontSA::PrintString(useCustomPosition ? properties.placement.customX : x, useCustomPosition ? properties.placement.customY : y, text); + float posX = useCustomPosition ? properties.placement.customX : x; + float posY = useCustomPosition ? properties.placement.customY : y; + + if (!drawFromBottom) + CFontSA::PrintString(posX, posY, text); + else + CFontSA::PrintStringFromBottom(posX, posY, text); } void CHudSA::RenderClock(float x, float y, const char* strTime) @@ -676,6 +771,136 @@ void CHudSA::RenderMoney(float x, float y, const char* strMoney) RenderText(x, y, strMoney, componentProperties.money, pGame->GetPlayerInfo()->GetPlayerMoney() < 0); } +void CHudSA::RenderAmmo(float x, float y, const char* strAmmo) +{ + RenderText(x, y, strAmmo, componentProperties.ammo); +} + +void CHudSA::RenderVehicleName(float x, float y, const char* vehName) +{ + RenderText(x, y, vehName, componentProperties.vehName, false, false, true); +} + +void CHudSA::RenderZoneName(float x, float y, const char* strArea) +{ + RenderText(x, y, strArea, componentProperties.areaName, false, true, true); +} + +void CHudSA::RenderRadioName(float x, float y, const char* strRadio) +{ + RenderText(x, y, strRadio, componentProperties.radioName, pGame->GetAERadioTrackManager()->IsStationLoading()); +} + +void __fastcall CHudSA::RenderWeaponIcon_Sprite(void* sprite, void*, CRect* rect, RwColor* color) +{ + // Use custom position/size? + SHudComponentData& properties = componentProperties.weaponIcon; + + bool useCustomPosition = properties.placement.useCustomPosition; + bool useCustomSize = properties.placement.useCustomSize; + + // Save default position once + if (!properties.placement.setDefaultXY) + { + properties.placement.x = rect->left; + properties.placement.y = rect->top; + properties.placement.setDefaultXY = true; + } + + if (useCustomPosition) + { + rect->left = properties.placement.customX; + rect->top = properties.placement.customY; + } + + if (useCustomPosition || useCustomSize) + { + rect->right = rect->left + (useCustomSize ? properties.placement.customWidth : properties.placement.width); + rect->bottom = rect->top + (useCustomSize ? properties.placement.customHeight : properties.placement.height); + } + + color->r = properties.fillColor_Second.r; + color->g = properties.fillColor_Second.g; + color->b = properties.fillColor_Second.b; + + if (properties.useCustomAlpha) + color->a = properties.fillColor_Second.a; + + // Call CSprite2d::Draw + ((void(__thiscall*)(void*, CRect*, RwColor*))FUNC_CSprie2d_Draw)(sprite, rect, color); +} + +void CHudSA::RenderWeaponIcon_XLU(CVector pos, CVector2D halfSize, std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint16_t intensity, float rhw, std::uint8_t a, std::uint8_t uDir, std::uint8_t vDir) +{ + // Use custom position/size? + SHudComponentData& properties = componentProperties.weaponIcon; + + bool useCustomPosition = properties.placement.useCustomPosition; + bool useCustomSize = properties.placement.useCustomSize; + + // Save default position once + if (!properties.placement.setDefaultXY) + { + properties.placement.x = pos.fX - halfSize.fX; + properties.placement.y = pos.fY - halfSize.fY; + properties.placement.setDefaultXY = true; + } + + float x = useCustomPosition ? properties.placement.customX : properties.placement.x; + float y = useCustomPosition ? properties.placement.customY : properties.placement.y; + float w = useCustomSize ? properties.placement.customWidth : properties.placement.width; + float h = useCustomSize ? properties.placement.customHeight : properties.placement.height; + + pos.fX = x + w * 0.5f; + pos.fY = y + h * 0.5f; + + if (useCustomSize) + { + halfSize.fX = w * 0.5f; + halfSize.fY = h * 0.5f; + } + + r = properties.fillColor.r; + g = properties.fillColor.g; + b = properties.fillColor.b; + + if (properties.useCustomAlpha) + { + a = properties.fillColor.a; + intensity = a; + } + + // Call CSprite::RenderOneXLUSprite + ((void(__cdecl*)(CVector, CVector2D, std::uint8_t, std::uint8_t, std::uint8_t, std::uint16_t, float, std::uint8_t, std::uint8_t, std::uint8_t))FUNC_CSprite_RenderOneXLUSprite)(pos, halfSize, r, g, b, intensity, rhw, a, uDir, vDir); +} + +void CHudSA::RenderWanted(bool empty, float x, float y, const char* strLevel) +{ + RenderText(x, y, strLevel, componentProperties.wanted, empty); +} + +static constexpr DWORD back = 0x58DFD8; +static void _declspec(naked) RenderWanted_Hook() +{ + _asm + { + cmp ebp, edi + jle empty + + push 0 + jmp render + + empty: + push 1 + + render: + call CHudSA::RenderWanted + add esp,4 + + jmp back + } +} + static void _declspec(naked) HOOK_RenderHudBar() { _asm @@ -734,4 +959,14 @@ void CHudSA::StaticSetHooks() HookInstallCall(0x58EC21, (DWORD)&RenderClock); HookInstallCall(0x58F607, (DWORD)&RenderMoney); + HookInstallCall(0x58962A, (DWORD)&RenderAmmo); + + HookInstallCall(0x58B156, (DWORD)&RenderVehicleName); + HookInstallCall(0x58AE5D, (DWORD)&RenderZoneName); + HookInstallCall(0x4E9FF1, (DWORD)&RenderRadioName); + + HookInstallCall(0x58D988, (DWORD)&RenderWeaponIcon_Sprite); + HookInstallCall(0x58D8FD, (DWORD)&RenderWeaponIcon_XLU); + + HookInstall(0x58DFD3, (DWORD)&RenderWanted_Hook); } diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index 7841e4dda4..a26dcba6e7 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -15,6 +15,7 @@ #include #include #include "CFontSA.h" +#include "CRect.h" #define FUNC_Draw 0x58FAE0 @@ -45,6 +46,8 @@ #define FUNC_CStats_GetFatAndMuscleModifier 0x559AF0 #define FUNC_CSprite2d_DrawBarChart 0x728640 +#define FUNC_CSprie2d_Draw 0x728350 +#define FUNC_CSprite_RenderOneXLUSprite 0x70D000 #define CODE_ShowMoney 0x58F47D @@ -121,12 +124,13 @@ struct SHudComponentData bool drawPercentage{false}; // Text - RwColor dropColor{}; + RwColor dropColor{0,0,0,255}; eFontAlignment alignment{}; eFontStyle style{}; std::int16_t textOutline{0}; std::int16_t textShadow{0}; bool proportional{false}; + bool useCustomAlpha{false}; SHudComponentData( RwColor fill = {}, @@ -138,7 +142,8 @@ struct SHudComponentData eFontStyle fontStyle = eFontStyle::FONT_PRICEDOWN, std::int16_t outline = 0, std::int16_t shadow = 0, - bool prop = false) : fillColor(fill), + bool prop = false, + bool useCustomAlpha = false) : fillColor(fill), fillColor_Second(fillSecond), drawBlackBorder(blackBorder), drawPercentage(percentage), @@ -147,7 +152,8 @@ struct SHudComponentData style(fontStyle), textOutline(outline), textShadow(shadow), - proportional(prop) {} + proportional(prop), + useCustomAlpha(useCustomAlpha) {} }; struct ComponentProperties @@ -158,6 +164,13 @@ struct ComponentProperties SHudComponentData clock; SHudComponentData money; + SHudComponentData ammo; + SHudComponentData vehName; + SHudComponentData areaName; + SHudComponentData radioName; + + SHudComponentData weaponIcon; + SHudComponentData wanted; }; class CHudSA : public CHud @@ -178,8 +191,8 @@ class CHudSA : public CHud void SetComponentPlacementPosition(SComponentPlacement& placement, const CVector2D& position) noexcept; void SetComponentPlacementSize(SComponentPlacement& placement, const CVector2D& size) noexcept; - void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept override; - void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept override; + void SetComponentPosition(const eHudComponent& component, const CVector2D& position) noexcept override { SetComponentPlacementPosition(GetHudComponentRef(component).placement, position); } + void SetComponentSize(const eHudComponent& component, const CVector2D& size) noexcept override { SetComponentPlacementSize(GetHudComponentRef(component).placement, size); } void ResetComponentPlacement(const eHudComponent& component, bool resetSize) noexcept override; @@ -197,12 +210,33 @@ class CHudSA : public CHud void SetComponentFontAlignment(const eHudComponent& component, const eFontAlignment& alignment) noexcept override { GetHudComponentRef(component).alignment = alignment; } void SetComponentFontProportional(const eHudComponent& component, bool proportional) noexcept override { GetHudComponentRef(component).proportional = proportional; } + void SetComponentUseCustomAlpha(const eHudComponent& component, bool useCustomAlpha) noexcept override { GetHudComponentRef(component).useCustomAlpha = useCustomAlpha; } + void ResetComponentFontOutline(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_OUTLINE); } void ResetComponentFontShadow(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_SHADOW); } void ResetComponentFontStyle(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_STYLE); } void ResetComponentFontAlignment(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_ALIGNMENT); } void ResetComponentFontProportional(const eHudComponent& component) noexcept override { ResetComponentFontData(component, eHudComponentProperty::TEXT_PROPORTIONAL); } + CVector2D GetComponentPosition(const eHudComponent& component) const noexcept override; + CVector2D GetComponentSize(const eHudComponent& component) const noexcept override; + + SColor GetComponentColor(const eHudComponent& component) const noexcept override; + SColor GetComponentSecondColor(const eHudComponent& component) const noexcept override; + SColor GetComponentFontDropColor(const eHudComponent& component) const override; + + bool GetComponentDrawBlackBorder(const eHudComponent& component) const noexcept override { return GetHudComponentRef(component).drawBlackBorder; } + bool GetComponentDrawPercentage(const eHudComponent& component) const noexcept override { return GetHudComponentRef(component).drawPercentage; } + float GetHealthBarBlinkingValue(const eHudComponent& component) const noexcept override { return CHudSA::blinkingBarHPValue; } + + float GetComponentFontOutline(const eHudComponent& component) const override { return CFontSA::GetEdge(); } + float GetComponentFontShadow(const eHudComponent& component) const override { return CFontSA::GetDropdownShadow(); } + eFontStyle GetComponentFontStyle(const eHudComponent& component) const override { return CFontSA::GetFontStyle(); } + eFontAlignment GetComponentFontAlignment(const eHudComponent& component) const override { return CFontSA::GetOrientation(); } + bool GetComponentFontProportional(const eHudComponent& component) const override { return CFontSA::GetProportional(); } + + bool GetComponentUseCustomAlpha(const eHudComponent& component) const noexcept override { return GetHudComponentRef(component).useCustomAlpha; } + static RsGlobal* GetRSGlobal() noexcept { return rsGlobal; } static RwColor GetHUDColour(const eHudColour& colour) noexcept; @@ -220,9 +254,18 @@ class CHudSA : public CHud static void RenderBreathBar(int x, int y); static void RenderArmorBar(int x, int y); - static void RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor = false); + static void RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor = false, bool drawFromBottom = false, bool scaleForLanguage = false); static void RenderClock(float x, float y, const char* strTime); static void RenderMoney(float x, float y, const char* strMoney); + static void RenderAmmo(float x, float y, const char* strAmmo); + static void RenderVehicleName(float x, float y, const char* vehName); + static void RenderZoneName(float x, float y, const char* strArea); + static void RenderRadioName(float x, float y, const char* strRadio); + + static void __fastcall RenderWeaponIcon_Sprite(void* sprite, void*, CRect* rect, RwColor* color); + static void RenderWeaponIcon_XLU(CVector pos, CVector2D halfSize, std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint16_t intensity, float rhw, std::uint8_t a, std::uint8_t uDir, std::uint8_t vDir); + + static void RenderWanted(bool empty, float x, float y, const char* strLevel); private: std::map m_HudComponentMap; diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 99eb78de34..cf80781971 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -3428,6 +3428,9 @@ void CClientGame::Event_OnIngame() pHud->SetComponentVisible(HUD_VITAL_STATS, false); pHud->SetComponentVisible(HUD_AREA_NAME, false); + // Reset properties + CLuaPlayerDefs::ResetPlayerHudComponentProperty(HUD_ALL, eHudComponentProperty::ALL_PROPERTIES); + g_pMultiplayer->DeleteAndDisableGangTags(); g_pGame->GetBuildingRemoval()->ClearRemovedBuildingLists(); diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 744e61877f..f10330fbc9 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -125,6 +125,7 @@ ADD_ENUM(eHudComponentProperty::TEXT_SHADOW, "fontShadow") ADD_ENUM(eHudComponentProperty::TEXT_STYLE, "fontStyle") ADD_ENUM(eHudComponentProperty::TEXT_ALIGNMENT, "fontAlignment") ADD_ENUM(eHudComponentProperty::TEXT_PROPORTIONAL, "proportional") +ADD_ENUM(eHudComponentProperty::CUSTOM_ALPHA, "useCustomAlpha") ADD_ENUM(eHudComponentProperty::ALL_PROPERTIES, "all") IMPLEMENT_ENUM_CLASS_END("hud-component-property") diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index fdf56a6372..3bf98beb0e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp @@ -53,6 +53,7 @@ void CLuaPlayerDefs::LoadFunctions() {"isPlayerMapVisible", IsPlayerMapVisible}, {"getPlayerMapBoundingBox", GetPlayerMapBoundingBox}, {"getPlayerMapOpacity", ArgumentParser}, + {"getPlayerHudComponentProperty", ArgumentParser}, }; // Add functions @@ -94,6 +95,7 @@ void CLuaPlayerDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "getNametagText", "getPlayerNametagText"); lua_classfunction(luaVM, "getNametagColor", "getPlayerNametagColor"); lua_classfunction(luaVM, "getScriptDebugLevel", "getPlayerScriptDebugLevel"); + lua_classfunction(luaVM, "getHudComponentProperty", "getPlayerHudComponentProperty"); lua_classfunction(luaVM, "isNametagShowing", "isPlayerNametagShowing"); lua_classfunction(luaVM, "isCrosshairVisible", "isPlayerCrosshairVisible"); @@ -649,8 +651,11 @@ bool CLuaPlayerDefs::IsPlayerCrosshairVisible() return g_pGame->GetHud()->IsCrosshairVisible(); } -bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value) +bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value) { + if (component == HUD_ALL || component == HUD_CROSSHAIR || component == HUD_VITAL_STATS || component == HUD_HELP_TEXT || component == HUD_RADAR) + return false; + CHud* hud = g_pGame->GetHud(); switch (property) @@ -674,7 +679,7 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud case eHudComponentProperty::FILL_COLOR: case eHudComponentProperty::FILL_COLOR_SECOND: { - if (!hud->IsComponentBar(component) && !hud->IsComponentText(component)) + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) return false; if (!std::holds_alternative(value)) @@ -754,14 +759,15 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!hud->IsComponentText(component)) return false; - if (!std::holds_alternative(value)) + if (!std::holds_alternative(value)) return false; - eFontStyle val = std::get(value); - if (val < eFontStyle::FONT_GOTHIC || val > eFontStyle::FONT_PRICEDOWN) + eFontStyle val; + if (!StringToEnum(std::get(value), val)) return false; - hud->SetComponentFontStyle(component, val); + // I don't know why, but calling StringToEnum causes the "hud" pointer to become invalid, leading to a crash + g_pGame->GetHud()->SetComponentFontStyle(component, val); return true; } case eHudComponentProperty::TEXT_ALIGNMENT: @@ -769,14 +775,15 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!hud->IsComponentText(component)) return false; - if (!std::holds_alternative(value)) + if (!std::holds_alternative(value)) return false; - eFontAlignment val = std::get(value); - if (val < eFontAlignment::ALIGN_CENTER || val > eFontAlignment::ALIGN_RIGHT) + eFontAlignment val; + if (!StringToEnum(std::get(value), val)) return false; - hud->SetComponentFontAlignment(component, val); + // I don't know why, but calling StringToEnum causes the "hud" pointer to become invalid, leading to a crash + g_pGame->GetHud()->SetComponentFontAlignment(component, val); return true; } case eHudComponentProperty::TEXT_PROPORTIONAL: @@ -790,20 +797,45 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud hud->SetComponentFontProportional(component, std::get(value)); return true; } + case eHudComponentProperty::CUSTOM_ALPHA: + { + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentUseCustomAlpha(component, std::get(value)); + return true; + } } return false; } -bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) +bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) noexcept { + if (component == HUD_CROSSHAIR || component == HUD_VITAL_STATS || component == HUD_HELP_TEXT || component == HUD_RADAR) + return false; + CHud* hud = g_pGame->GetHud(); + if (component == HUD_ALL) + { + for (std::size_t iComp = 0; iComp < static_cast(HUD_HELP_TEXT); iComp++) + { + eHudComponent comp = static_cast(iComp); + if (comp == HUD_ALL) + continue; + + ResetPlayerHudComponentProperty(comp, property); + } + + return true; + } + switch (property) { case eHudComponentProperty::ALL_PROPERTIES: { - for (int i = 0; i < static_cast(eHudComponentProperty::ALL_PROPERTIES); i++) + for (std::size_t i = 0; i < static_cast(eHudComponentProperty::ALL_PROPERTIES); i++) ResetPlayerHudComponentProperty(component, static_cast(i)); return true; @@ -817,10 +849,14 @@ bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eH case eHudComponentProperty::FILL_COLOR: case eHudComponentProperty::FILL_COLOR_SECOND: { - if (!hud->IsComponentBar(component) && !hud->IsComponentText(component)) + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) + return false; + + bool second = property == eHudComponentProperty::FILL_COLOR_SECOND; + if (second && (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON)) return false; - hud->ResetComponentColor(component, property == eHudComponentProperty::FILL_COLOR_SECOND); + hud->ResetComponentColor(component, second); return true; } case eHudComponentProperty::DROP_COLOR: @@ -895,7 +931,116 @@ bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eH hud->ResetComponentFontProportional(component); return true; } + case eHudComponentProperty::CUSTOM_ALPHA: + hud->SetComponentUseCustomAlpha(component, false); + return true; } return false; } + +std::variant, CLuaMultiReturn> CLuaPlayerDefs::GetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) +{ + if (component == HUD_ALL || component == HUD_CROSSHAIR || component == HUD_VITAL_STATS || component == HUD_HELP_TEXT || component == HUD_RADAR) + return false; + + CHud* hud = g_pGame->GetHud(); + + switch (property) + { + case eHudComponentProperty::POSITION: + { + CVector2D& pos = hud->GetComponentPosition(component); + return CLuaMultiReturn{pos.fX, pos.fY}; + } + case eHudComponentProperty::SIZE: + { + CVector2D& size = hud->GetComponentSize(component); + return CLuaMultiReturn{size.fX, size.fY}; + } + case eHudComponentProperty::FILL_COLOR: + { + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) + return false; + + SColor& color = hud->GetComponentColor(component); + return CLuaMultiReturn{color.R, color.G, color.B, color.A}; + } + case eHudComponentProperty::FILL_COLOR_SECOND: + { + if (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON) + return false; + + SColor& color = hud->GetComponentSecondColor(component); + return CLuaMultiReturn{color.R, color.G, color.B, color.A}; + } + case eHudComponentProperty::DROP_COLOR: + { + if (!hud->IsComponentText(component)) + return false; + + SColor& color = hud->GetComponentFontDropColor(component); + return CLuaMultiReturn{color.R, color.G, color.B, color.A}; + } + case eHudComponentProperty::DRAW_BLACK_BORDER: + { + if (!hud->IsComponentBar(component)) + return false; + + return hud->GetComponentDrawBlackBorder(component); + } + case eHudComponentProperty::DRAW_PERCENTAGE: + { + if (!hud->IsComponentBar(component)) + return false; + + return hud->GetComponentDrawPercentage(component); + } + case eHudComponentProperty::BLINKING_HP_VALUE: + { + if (component != HUD_HEALTH) + return false; + + return hud->GetHealthBarBlinkingValue(component); + } + case eHudComponentProperty::TEXT_OUTLINE: + { + if (!hud->IsComponentText(component)) + return false; + + return hud->GetComponentFontOutline(component); + } + case eHudComponentProperty::TEXT_SHADOW: + { + if (!hud->IsComponentText(component)) + return false; + + return hud->GetComponentFontShadow(component); + } + case eHudComponentProperty::TEXT_STYLE: + { + if (!hud->IsComponentText(component)) + return false; + + return EnumToString(hud->GetComponentFontStyle(component)); + } + case eHudComponentProperty::TEXT_ALIGNMENT: + { + if (!hud->IsComponentText(component)) + return false; + + return EnumToString(hud->GetComponentFontAlignment(component)); + } + case eHudComponentProperty::TEXT_PROPORTIONAL: + { + if (!hud->IsComponentText(component)) + return false; + + return hud->GetComponentFontProportional(component); + } + case eHudComponentProperty::CUSTOM_ALPHA: + return hud->GetComponentUseCustomAlpha(component); + } + + return false; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h index 34fe6c7c4d..e7737fbd2e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h @@ -31,6 +31,7 @@ class CLuaPlayerDefs : public CLuaDefs LUA_DECLARE(GetPlayerWantedLevel); static std::uint8_t GetPlayerScriptDebugLevel() noexcept; static bool IsPlayerCrosshairVisible(); + static std::variant, CLuaMultiReturn> GetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property); // Player set LUA_DECLARE(ShowPlayerHudComponent); @@ -41,8 +42,8 @@ class CLuaPlayerDefs : public CLuaDefs LUA_DECLARE(SetPlayerNametagText); LUA_DECLARE(SetPlayerNametagColor); LUA_DECLARE(SetPlayerNametagShowing); - static bool SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value); - static bool ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property); + static bool SetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property, std::variant value); + static bool ResetPlayerHudComponentProperty(eHudComponent component, eHudComponentProperty property) noexcept; // Community funcs LUA_DECLARE(GetPlayerUserName); diff --git a/Client/sdk/game/CAERadioTrackManager.h b/Client/sdk/game/CAERadioTrackManager.h index e07c20a7ce..bd7a619cc7 100644 --- a/Client/sdk/game/CAERadioTrackManager.h +++ b/Client/sdk/game/CAERadioTrackManager.h @@ -21,4 +21,5 @@ class CAERadioTrackManager virtual void SetBassSetting(DWORD dwBass) = 0; virtual void Reset() = 0; virtual void StartRadio(BYTE bStationID, BYTE bUnknown) = 0; + virtual bool IsStationLoading() const = 0; }; diff --git a/Client/sdk/game/CHud.h b/Client/sdk/game/CHud.h index e6a3594b7f..6dd2cc5ee1 100644 --- a/Client/sdk/game/CHud.h +++ b/Client/sdk/game/CHud.h @@ -48,19 +48,20 @@ enum class eHudComponentProperty TEXT_STYLE, TEXT_ALIGNMENT, TEXT_PROPORTIONAL, + CUSTOM_ALPHA, ALL_PROPERTIES, }; -enum class eFontStyle +enum class eFontStyle : std::uint8_t { - FONT_GOTHIC = 0, + FONT_GOTHIC, FONT_SUBTITLES, FONT_MENU, FONT_PRICEDOWN, }; -enum class eFontAlignment +enum class eFontAlignment : std::uint8_t { ALIGN_CENTER, ALIGN_LEFT, @@ -100,9 +101,30 @@ class CHud virtual void SetComponentFontAlignment(const eHudComponent& component, const eFontAlignment& alignment) noexcept = 0; virtual void SetComponentFontProportional(const eHudComponent& component, bool proportional) noexcept = 0; + virtual void SetComponentUseCustomAlpha(const eHudComponent& component, bool useCustomAlpha) noexcept = 0; + virtual void ResetComponentFontOutline(const eHudComponent& component) noexcept = 0; virtual void ResetComponentFontShadow(const eHudComponent& component) noexcept = 0; virtual void ResetComponentFontStyle(const eHudComponent& component) noexcept = 0; virtual void ResetComponentFontAlignment(const eHudComponent& component) noexcept = 0; virtual void ResetComponentFontProportional(const eHudComponent& component) noexcept = 0; + + virtual CVector2D GetComponentPosition(const eHudComponent& component) const noexcept = 0; + virtual CVector2D GetComponentSize(const eHudComponent& component) const noexcept = 0; + + virtual SColor GetComponentColor(const eHudComponent& component) const noexcept = 0; + virtual SColor GetComponentSecondColor(const eHudComponent& component) const noexcept = 0; + virtual SColor GetComponentFontDropColor(const eHudComponent& component) const = 0; + + virtual bool GetComponentDrawBlackBorder(const eHudComponent& component) const noexcept = 0; + virtual bool GetComponentDrawPercentage(const eHudComponent& component) const noexcept = 0; + virtual float GetHealthBarBlinkingValue(const eHudComponent& component) const noexcept = 0; + + virtual float GetComponentFontOutline(const eHudComponent& component) const = 0; + virtual float GetComponentFontShadow(const eHudComponent& component) const = 0; + virtual eFontStyle GetComponentFontStyle(const eHudComponent& component) const = 0; + virtual eFontAlignment GetComponentFontAlignment(const eHudComponent& component) const = 0; + virtual bool GetComponentFontProportional(const eHudComponent& component) const = 0; + + virtual bool GetComponentUseCustomAlpha(const eHudComponent& component) const noexcept = 0; }; From 5546c04bbf3f3d23fa98b80e3c85b0594c69ae0f Mon Sep 17 00:00:00 2001 From: FileEX Date: Fri, 27 Dec 2024 00:39:15 +0100 Subject: [PATCH 4/5] textSize property --- Client/game_sa/CHudSA.cpp | 27 ++++++++++++------- Client/game_sa/CHudSA.h | 3 +++ .../logic/lua/CLuaFunctionParseHelpers.cpp | 1 + .../logic/luadefs/CLuaPlayerDefs.cpp | 5 ++++ Client/sdk/game/CHud.h | 3 +++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Client/game_sa/CHudSA.cpp b/Client/game_sa/CHudSA.cpp index b30eb03589..ba9358e254 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -369,6 +369,12 @@ bool CHudSA::IsComponentText(const eHudComponent& component) const noexcept return false; } +CVector2D CHudSA::GetComponentTextSize(const eHudComponent& component) const +{ + const auto& ref = GetHudComponentRef(component); + return CVector2D(ref.placement.stringWidth, ref.placement.stringHeight); +} + RwColor CHudSA::GetHUDColour(const eHudColour& colour) noexcept { switch (colour) @@ -710,14 +716,6 @@ void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& p bool useCustomPosition = properties.placement.useCustomPosition; bool useCustomSize = properties.placement.useCustomSize; - // Save default position once - if (!properties.placement.setDefaultXY) - { - properties.placement.x = x; - properties.placement.y = y; - properties.placement.setDefaultXY = true; - } - float scaleX = useCustomSize ? properties.placement.customWidth : properties.placement.width; float scaleY = useCustomSize ? properties.placement.customHeight : properties.placement.height; @@ -750,7 +748,18 @@ void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& p CFontSA::SetDropColor(properties.dropColor); CFontSA::SetColor(useSecondColor ? properties.fillColor_Second : properties.fillColor); } - + + // Save default position once + if (!properties.placement.setDefaultXY) + { + properties.placement.x = x; + properties.placement.y = y; + properties.placement.stringWidth = CFontSA::GetStringWidth(text, true); + properties.placement.stringHeight = CFontSA::GetFontHeight(CFontSA::GetScale().fY); + + properties.placement.setDefaultXY = true; + } + // Draw text float posX = useCustomPosition ? properties.placement.customX : x; float posY = useCustomPosition ? properties.placement.customY : y; diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index a26dcba6e7..81dd6c3546 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -103,6 +103,7 @@ struct SComponentPlacement // Original position & size float x{0.0f}, y{0.0f}; // for getter function only float width{0.0f}, height{0.0f}; + float stringWidth{0.0f}, stringHeight{0.0f}; // for getter function only // Custom position & size float customX{0.0f}, customY{0.0f}; @@ -237,6 +238,8 @@ class CHudSA : public CHud bool GetComponentUseCustomAlpha(const eHudComponent& component) const noexcept override { return GetHudComponentRef(component).useCustomAlpha; } + CVector2D GetComponentTextSize(const eHudComponent& component) const override; + static RsGlobal* GetRSGlobal() noexcept { return rsGlobal; } static RwColor GetHUDColour(const eHudColour& colour) noexcept; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index f10330fbc9..ba9b0e1b60 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -126,6 +126,7 @@ ADD_ENUM(eHudComponentProperty::TEXT_STYLE, "fontStyle") ADD_ENUM(eHudComponentProperty::TEXT_ALIGNMENT, "fontAlignment") ADD_ENUM(eHudComponentProperty::TEXT_PROPORTIONAL, "proportional") ADD_ENUM(eHudComponentProperty::CUSTOM_ALPHA, "useCustomAlpha") +ADD_ENUM(eHudComponentProperty::TEXT_SIZE, "textSize") ADD_ENUM(eHudComponentProperty::ALL_PROPERTIES, "all") IMPLEMENT_ENUM_CLASS_END("hud-component-property") diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index 3bf98beb0e..3dd45e8ffd 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp @@ -1040,6 +1040,11 @@ std::variant, CLuaMultiR } case eHudComponentProperty::CUSTOM_ALPHA: return hud->GetComponentUseCustomAlpha(component); + case eHudComponentProperty::TEXT_SIZE: + { + CVector2D& size = hud->GetComponentTextSize(component); + return CLuaMultiReturn{size.fX, size.fY}; + } } return false; diff --git a/Client/sdk/game/CHud.h b/Client/sdk/game/CHud.h index 6dd2cc5ee1..56acc80cb5 100644 --- a/Client/sdk/game/CHud.h +++ b/Client/sdk/game/CHud.h @@ -49,6 +49,7 @@ enum class eHudComponentProperty TEXT_ALIGNMENT, TEXT_PROPORTIONAL, CUSTOM_ALPHA, + TEXT_SIZE, ALL_PROPERTIES, }; @@ -127,4 +128,6 @@ class CHud virtual bool GetComponentFontProportional(const eHudComponent& component) const = 0; virtual bool GetComponentUseCustomAlpha(const eHudComponent& component) const noexcept = 0; + + virtual CVector2D GetComponentTextSize(const eHudComponent& component) const = 0; }; From 4ae354e3a07b04685e57dd19f6d8a5cf1484f716 Mon Sep 17 00:00:00 2001 From: FileEX Date: Tue, 31 Dec 2024 02:22:08 +0100 Subject: [PATCH 5/5] Review --- Client/game_sa/CFontSA.cpp | 44 +++++----- Client/game_sa/CFontSA.h | 33 -------- Client/game_sa/CHudSA.cpp | 84 +++++-------------- Client/game_sa/CHudSA.h | 16 ++-- .../logic/lua/CLuaFunctionParseHelpers.cpp | 2 +- .../logic/luadefs/CLuaPlayerDefs.cpp | 12 +-- Client/sdk/game/CHud.h | 4 +- .../deathmatch/logic/luadefs/CLuaBitDefs.cpp | 6 +- Shared/sdk/SharedUtil.Defines.h | 2 +- Shared/sdk/SharedUtil.Misc.h | 8 +- 10 files changed, 69 insertions(+), 142 deletions(-) diff --git a/Client/game_sa/CFontSA.cpp b/Client/game_sa/CFontSA.cpp index bf17b8a1dd..d9a724285c 100644 --- a/Client/game_sa/CFontSA.cpp +++ b/Client/game_sa/CFontSA.cpp @@ -15,25 +15,25 @@ void CFontSA::PrintChar(float x, float y, char character) { // Call CFont::PrintChar - ((void(_cdecl*)(float, float, char))FUNC_CFont_PrintChar)(x, y, character); + ((void(_cdecl*)(float, float, char))0x718A10)(x, y, character); } void CFontSA::PrintString(float x, float y, const char* text) { // Call CFont::PrintString - ((void(__cdecl*)(float, float, const char*))FUNC_CFont_PrintString)(x, y, text); + ((void(__cdecl*)(float, float, const char*))0x71A700)(x, y, text); } void CFontSA::PrintStringFromBottom(float x, float y, const char* text) { // Call CFont::PrintStringFromBottom - ((void(__cdecl*)(float, float, const char*))FUNC_CFont_PrintStringFromBottom)(x, y, text); + ((void(__cdecl*)(float, float, const char*))0x71A820)(x, y, text); } void CFontSA::SetScale(float w, float h) { // Call CFont::SetScale - ((void(__cdecl*)(float, float))FUNC_CFont_SetScale)(w, h); + ((void(__cdecl*)(float, float))0x719380)(w, h); } void CFontSA::SetScale(const CVector2D& scale) @@ -44,109 +44,109 @@ void CFontSA::SetScale(const CVector2D& scale) void CFontSA::SetScaleForCurrentLanguage(float w, float h) { // Call CFont::SetScaleForCurrentLanguage - ((void(__cdecl*)(float, float))FUNC_CFont_SetScaleForCurrentLanguage)(w, h); + ((void(__cdecl*)(float, float))0x7193A0)(w, h); } void CFontSA::SetSlantRefPoint(float x, float y) { // Call CFont::SetSlantRefPoint - ((void(__cdecl*)(float, float))FUNC_CFont_SetSlantRefPoint)(x, y); + ((void(__cdecl*)(float, float))0x719400)(x, y); } void CFontSA::SetSlant(float slant) { // Call CFont::SetSlant - ((void(__cdecl*)(float))FUNC_CFont_SetSlant)(slant); + ((void(__cdecl*)(float))0x719420)(slant); } void CFontSA::SetColor(const RwColor& color) { // Call CFont::SetColor - ((void(__cdecl*)(RwColor))FUNC_CFont_SetColor)(color); + ((void(__cdecl*)(RwColor))0x719430)(color); } void CFontSA::SetDropColor(const RwColor& color) { // Call CFont::SetDropColor - ((void(__cdecl*)(RwColor))FUNC_CFont_SetDropColor)(color); + ((void(__cdecl*)(RwColor))0x719510)(color); } void CFontSA::SetFontStyle(const eFontStyle& style) { // Call CFont::SetFontStyle - ((void(__cdecl*)(eFontStyle))FUNC_CFont_SetStyle)(style); + ((void(__cdecl*)(eFontStyle))0x719490)(style); } void CFontSA::SetWrapX(float wrapx) { // Call CFont::SetWrapx - ((void(__cdecl*)(float))FUNC_CFont_SetWrapX)(wrapx); + ((void(__cdecl*)(float))0x7194D0)(wrapx); } void CFontSA::SetRightJustifyWrap(float wrap) { // Call CFont::SetRightJustifyWrap - ((void(__cdecl*)(float))FUNC_CFont_SetRightJustifyWrap)(wrap); + ((void(__cdecl*)(float))0x7194F0)(wrap); } void CFontSA::SetCentreSize(float size) { // Call CFont::SetCentreSize - ((void(__cdecl*)(float))FUNC_CFont_SetCentreSize)(size); + ((void(__cdecl*)(float))0x7194E0)(size); } void CFontSA::SetDropShadowPosition(std::int16_t offset) { // Call CFont::SetDropShadowPosition - ((void(__cdecl*)(std::int16_t))FUNC_CFont_SetDropShadowPosition)(offset); + ((void(__cdecl*)(std::int16_t))0x719570)(offset); } void CFontSA::SetEdge(std::int16_t edgeSize) { // Call CFont::SetEdge - ((void(__cdecl*)(std::int16_t))FUNC_CFont_SetEdge)(edgeSize); + ((void(__cdecl*)(std::int16_t))0x719590)(edgeSize); } void CFontSA::SetProportional(bool enable) { // Call CFont::SetProportional - ((void(__cdecl*)(bool))FUNC_CFont_SetProportional)(enable); + ((void(__cdecl*)(bool))0x7195B0)(enable); } void CFontSA::SetBackground(bool enable, bool includeWrap) { // Call CFont::SetBackground - ((void(__cdecl*)(bool, bool))FUNC_CFont_SetBackground)(enable, includeWrap); + ((void(__cdecl*)(bool, bool))0x7195C0)(enable, includeWrap); } void CFontSA::SetBackgroundColor(const RwColor& color) { // Call CFont::SetBackgroundColor - ((void(__cdecl*)(RwColor))FUNC_CFont_SetBackgroundColor)(color); + ((void(__cdecl*)(RwColor))0x7195E0)(color); } void CFontSA::SetJustify(bool enable) { // Call CFont::SetJustify - ((void(__cdecl*)(bool))FUNC_CFont_SetJustify)(enable); + ((void(__cdecl*)(bool))0x719600)(enable); } void CFontSA::SetOrientation(const eFontAlignment& alignment) { // Call CFont::SetOrientation - ((void(__cdecl*)(eFontAlignment))FUNC_CFont_SetOrientation)(alignment); + ((void(__cdecl*)(eFontAlignment))0x719610)(alignment); } float CFontSA::GetStringWidth(const char* string, bool spaces, bool scriptValues) { // Call CFont::GetStringWidth - return ((float(__cdecl*)(const char*, bool, bool))FUNC_CFont_GetStringWidth)(string, spaces, scriptValues); + return ((float(__cdecl*)(const char*, bool, bool))0x71A0E0)(string, spaces, scriptValues); } std::int16_t CFontSA::GetNumberLines(float x, float y, const char* text) { // Call CFont::GetNumberLines - return ((std::int16_t(__cdecl*)(float, float, const char*))FUNC_CFont_GetNumberLines)(x, y, text); + return ((std::int16_t(__cdecl*)(float, float, const char*))0x71A5E0)(x, y, text); } float CFontSA::GetFontHeight(float scaleY) diff --git a/Client/game_sa/CFontSA.h b/Client/game_sa/CFontSA.h index 6c5b0a5cdd..2d724be8bf 100644 --- a/Client/game_sa/CFontSA.h +++ b/Client/game_sa/CFontSA.h @@ -14,39 +14,6 @@ #include #include -#define FUNC_CFont_PrintChar 0x718A10 -#define FUNC_CFont_PrintString 0x71A700 -#define FUNC_CFont_PrintStringFromBottom 0x71A820 - -#define FUNC_CFont_SetScale 0x719380 -#define FUNC_CFont_SetScaleForCurrentLanguage 0x7193A0 - -#define FUNC_CFont_SetSlantRefPoint 0x719400 -#define FUNC_CFont_SetSlant 0x719420 - -#define FUNC_CFont_SetStyle 0x719490 -#define FUNC_CFont_SetCentreSize 0x7194E0 - -#define FUNC_CFont_SetWrapX 0x7194D0 -#define FUNC_CFont_SetRightJustifyWrap 0x7194F0 - -#define FUNC_CFont_SetColor 0x719430 -#define FUNC_CFont_SetDropColor 0x719510 - -#define FUNC_CFont_SetDropShadowPosition 0x719570 -#define FUNC_CFont_SetEdge 0x719590 - -#define FUNC_CFont_SetProportional 0x7195B0 - -#define FUNC_CFont_SetBackground 0x7195C0 -#define FUNC_CFont_SetBackgroundColor 0x7195E0 - -#define FUNC_CFont_SetJustify 0x719600 -#define FUNC_CFont_SetOrientation 0x719610 - -#define FUNC_CFont_GetStringWidth 0x71A0E0 -#define FUNC_CFont_GetNumberLines 0x71A5E0 - #define VAR_CFont_Scale 0xC71A64 #define VAR_CFont_Color 0xC71A60 diff --git a/Client/game_sa/CHudSA.cpp b/Client/game_sa/CHudSA.cpp index ba9358e254..887f39eb89 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -41,6 +41,7 @@ DrawBarChartFunc DrawBarChart = reinterpret_cast(FUNC_CSprite2 std::unordered_map defaultComponentProperties = { {HUD_HEALTH, {CHudSA::GetHUDColour(eHudColour::RED)}}, {HUD_BREATH, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE)}}, + {HUD_ARMOUR, {CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY)}}, {HUD_CLOCK, {CHudSA::GetHUDColour(eHudColour::LIGHT_GRAY), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}}, {HUD_MONEY, {CHudSA::GetHUDColour(eHudColour::GREEN), CHudSA::GetHUDColour(eHudColour::RED), false, false, COLOR_BLACK, eFontAlignment::ALIGN_RIGHT, eFontStyle::FONT_PRICEDOWN, 2}}, {HUD_AMMO, {CHudSA::GetHUDColour(eHudColour::LIGHT_BLUE), {}, false, false, COLOR_BLACK, eFontAlignment::ALIGN_CENTER, eFontStyle::FONT_SUBTITLES, 1, 0, true}}, @@ -543,7 +544,7 @@ void CHudSA::SetComponentColor(const eHudComponent& component, std::uint32_t col if (!secondColor) compRef.fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; else - compRef.fillColor_Second = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; + compRef.fillColorSecondary = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; } void CHudSA::ResetComponentColor(const eHudComponent& component, bool secondColor) noexcept @@ -557,7 +558,7 @@ void CHudSA::ResetComponentColor(const eHudComponent& component, bool secondColo if (!secondColor) componentData.fillColor = defaultRef.fillColor; else - componentData.fillColor_Second = defaultRef.fillColor_Second; + componentData.fillColorSecondary = defaultRef.fillColorSecondary; } void CHudSA::SetComponentFontDropColor(const eHudComponent& component, std::uint32_t color) noexcept @@ -592,10 +593,10 @@ SColor CHudSA::GetComponentColor(const eHudComponent& component) const noexcept return SColorRGBA(ref.fillColor.r, ref.fillColor.g, ref.fillColor.b, ref.fillColor.a); } -SColor CHudSA::GetComponentSecondColor(const eHudComponent& component) const noexcept +SColor CHudSA::GetComponentSecondaryColor(const eHudComponent& component) const noexcept { const auto& ref = GetHudComponentRef(component); - return SColorRGBA(ref.fillColor_Second.r, ref.fillColor_Second.g, ref.fillColor_Second.b, ref.fillColor_Second.a); + return SColorRGBA(ref.fillColorSecondary.r, ref.fillColorSecondary.g, ref.fillColorSecondary.b, ref.fillColorSecondary.a); } SColor CHudSA::GetComponentFontDropColor(const eHudComponent& component) const @@ -741,12 +742,12 @@ void CHudSA::RenderText(float x, float y, const char* text, SHudComponentData& p if (!properties.useCustomAlpha) { CFontSA::SetDropColor(RwColor{properties.dropColor.r, properties.dropColor.g, properties.dropColor.b, CFontSA::GetColor().a}); - CFontSA::SetColor(useSecondColor ? RwColor{properties.fillColor_Second.r, properties.fillColor_Second.g, properties.fillColor_Second.b, CFontSA::GetColor().a} : RwColor{properties.fillColor.r, properties.fillColor.g, properties.fillColor.b, CFontSA::GetColor().a}); + CFontSA::SetColor(useSecondColor ? RwColor{properties.fillColorSecondary.r, properties.fillColorSecondary.g, properties.fillColorSecondary.b, CFontSA::GetColor().a} : RwColor{properties.fillColor.r, properties.fillColor.g, properties.fillColor.b, CFontSA::GetColor().a}); } else { CFontSA::SetDropColor(properties.dropColor); - CFontSA::SetColor(useSecondColor ? properties.fillColor_Second : properties.fillColor); + CFontSA::SetColor(useSecondColor ? properties.fillColorSecondary : properties.fillColor); } // Save default position once @@ -828,12 +829,12 @@ void __fastcall CHudSA::RenderWeaponIcon_Sprite(void* sprite, void*, CRect* rect rect->bottom = rect->top + (useCustomSize ? properties.placement.customHeight : properties.placement.height); } - color->r = properties.fillColor_Second.r; - color->g = properties.fillColor_Second.g; - color->b = properties.fillColor_Second.b; + color->r = properties.fillColorSecondary.r; + color->g = properties.fillColorSecondary.g; + color->b = properties.fillColorSecondary.b; if (properties.useCustomAlpha) - color->a = properties.fillColor_Second.a; + color->a = properties.fillColorSecondary.a; // Call CSprite2d::Draw ((void(__thiscall*)(void*, CRect*, RwColor*))FUNC_CSprie2d_Draw)(sprite, rect, color); @@ -888,8 +889,8 @@ void CHudSA::RenderWanted(bool empty, float x, float y, const char* strLevel) RenderText(x, y, strLevel, componentProperties.wanted, empty); } -static constexpr DWORD back = 0x58DFD8; -static void _declspec(naked) RenderWanted_Hook() +static constexpr std::uintptr_t CONTINUE_RenderWanted = 0x58DFD8; +static void _declspec(naked) HOOK_RenderWanted() { _asm { @@ -906,58 +907,19 @@ static void _declspec(naked) RenderWanted_Hook() call CHudSA::RenderWanted add esp,4 - jmp back + jmp CONTINUE_RenderWanted } } -static void _declspec(naked) HOOK_RenderHudBar() +static void HOOK_RenderHudBar(int playerId, int x, int y) { - _asm - { - mov eax, [esp] - - push [esp+0Ch] // y - push [esp+0Ch] // x - - // Health bar - cmp eax, 0058EE9Fh - jz renderHealthBar - - cmp eax, 0058EF12h - jz renderHealthBar - - // Breath bar - cmp eax, 0058F136h - jz renderBreathBar - - cmp eax, 0058F1B2h - jz renderBreathBar - - // Armor bar - cmp eax, 0058EF70h - jz renderArmorBar - - cmp eax, 0058EFE3h - jz renderArmorBar - - jmp skip - - renderHealthBar: - call CHudSA::RenderHealthBar - jmp skip - - renderBreathBar: - call CHudSA::RenderBreathBar - jmp skip - - renderArmorBar: - call CHudSA::RenderArmorBar - jmp skip - - skip: - add esp, 8 - retn - } + void* returnAdress = _ReturnAddress(); + if (returnAdress == (void*)0x58EE9F || returnAdress == (void*)0x58EF12) + CHudSA::RenderHealthBar(x, y); + else if (returnAdress == (void*)0x58F136 || returnAdress == (void*)0x58F1B2) + CHudSA::RenderBreathBar(x, y); + else if (returnAdress == (void*)0x58EF70 || returnAdress == (void*)0x58EFE3) + CHudSA::RenderArmorBar(x, y); } void CHudSA::StaticSetHooks() @@ -977,5 +939,5 @@ void CHudSA::StaticSetHooks() HookInstallCall(0x58D988, (DWORD)&RenderWeaponIcon_Sprite); HookInstallCall(0x58D8FD, (DWORD)&RenderWeaponIcon_XLU); - HookInstall(0x58DFD3, (DWORD)&RenderWanted_Hook); + HookInstall(0x58DFD3, &HOOK_RenderWanted); } diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index 81dd6c3546..479d60a82b 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -118,7 +118,7 @@ struct SHudComponentData { SComponentPlacement placement{}; RwColor fillColor{}; - RwColor fillColor_Second{0,0,0,255}; + RwColor fillColorSecondary{0,0,0,255}; // Bar bool drawBlackBorder{true}; @@ -135,7 +135,7 @@ struct SHudComponentData SHudComponentData( RwColor fill = {}, - RwColor fillSecond = {0, 0, 0, 255}, + RwColor fillSecondary = {0, 0, 0, 255}, bool blackBorder = true, bool percentage = false, RwColor drop = {}, @@ -145,7 +145,7 @@ struct SHudComponentData std::int16_t shadow = 0, bool prop = false, bool useCustomAlpha = false) : fillColor(fill), - fillColor_Second(fillSecond), + fillColorSecondary(fillSecondary), drawBlackBorder(blackBorder), drawPercentage(percentage), dropColor(drop), @@ -223,7 +223,7 @@ class CHudSA : public CHud CVector2D GetComponentSize(const eHudComponent& component) const noexcept override; SColor GetComponentColor(const eHudComponent& component) const noexcept override; - SColor GetComponentSecondColor(const eHudComponent& component) const noexcept override; + SColor GetComponentSecondaryColor(const eHudComponent& component) const noexcept override; SColor GetComponentFontDropColor(const eHudComponent& component) const override; bool GetComponentDrawBlackBorder(const eHudComponent& component) const noexcept override { return GetHudComponentRef(component).drawBlackBorder; } @@ -245,6 +245,10 @@ class CHudSA : public CHud static void StaticSetHooks(); + static void RenderHealthBar(int x, int y); + static void RenderBreathBar(int x, int y); + static void RenderArmorBar(int x, int y); + private: void InitComponentList(); void UpdateStreetchCalculations(); @@ -253,10 +257,6 @@ class CHudSA : public CHud SHudComponentData& GetHudComponentRef(const eHudComponent& component) const noexcept; - static void RenderHealthBar(int x, int y); - static void RenderBreathBar(int x, int y); - static void RenderArmorBar(int x, int y); - static void RenderText(float x, float y, const char* text, SHudComponentData& properties, bool useSecondColor = false, bool drawFromBottom = false, bool scaleForLanguage = false); static void RenderClock(float x, float y, const char* strTime); static void RenderMoney(float x, float y, const char* strMoney); diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index ba9b0e1b60..43f57a637d 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -115,7 +115,7 @@ IMPLEMENT_ENUM_CLASS_BEGIN(eHudComponentProperty) ADD_ENUM(eHudComponentProperty::POSITION, "position") ADD_ENUM(eHudComponentProperty::SIZE, "size") ADD_ENUM(eHudComponentProperty::FILL_COLOR, "fillColor") -ADD_ENUM(eHudComponentProperty::FILL_COLOR_SECOND, "fillColor_second") +ADD_ENUM(eHudComponentProperty::FILL_COLOR_SECONDARY, "fillColorSecondary") ADD_ENUM(eHudComponentProperty::DRAW_BLACK_BORDER, "drawBlackBorder") ADD_ENUM(eHudComponentProperty::DRAW_PERCENTAGE, "drawPercentage") ADD_ENUM(eHudComponentProperty::BLINKING_HP_VALUE, "blinkingValue") diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index 3dd45e8ffd..4702e9ce3d 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp @@ -677,7 +677,7 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud return true; } case eHudComponentProperty::FILL_COLOR: - case eHudComponentProperty::FILL_COLOR_SECOND: + case eHudComponentProperty::FILL_COLOR_SECONDARY: { if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) return false; @@ -685,7 +685,7 @@ bool CLuaPlayerDefs::SetPlayerHudComponentProperty(eHudComponent component, eHud if (!std::holds_alternative(value)) return false; - hud->SetComponentColor(component, static_cast(std::get(value)), property == eHudComponentProperty::FILL_COLOR_SECOND); + hud->SetComponentColor(component, static_cast(std::get(value)), property == eHudComponentProperty::FILL_COLOR_SECONDARY); return true; } case eHudComponentProperty::DRAW_BLACK_BORDER: @@ -847,12 +847,12 @@ bool CLuaPlayerDefs::ResetPlayerHudComponentProperty(eHudComponent component, eH hud->ResetComponentPlacement(component, true); return true; case eHudComponentProperty::FILL_COLOR: - case eHudComponentProperty::FILL_COLOR_SECOND: + case eHudComponentProperty::FILL_COLOR_SECONDARY: { if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) return false; - bool second = property == eHudComponentProperty::FILL_COLOR_SECOND; + bool second = property == eHudComponentProperty::FILL_COLOR_SECONDARY; if (second && (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON)) return false; @@ -966,12 +966,12 @@ std::variant, CLuaMultiR SColor& color = hud->GetComponentColor(component); return CLuaMultiReturn{color.R, color.G, color.B, color.A}; } - case eHudComponentProperty::FILL_COLOR_SECOND: + case eHudComponentProperty::FILL_COLOR_SECONDARY: { if (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON) return false; - SColor& color = hud->GetComponentSecondColor(component); + SColor& color = hud->GetComponentSecondaryColor(component); return CLuaMultiReturn{color.R, color.G, color.B, color.A}; } case eHudComponentProperty::DROP_COLOR: diff --git a/Client/sdk/game/CHud.h b/Client/sdk/game/CHud.h index 56acc80cb5..403a0e73fb 100644 --- a/Client/sdk/game/CHud.h +++ b/Client/sdk/game/CHud.h @@ -36,7 +36,7 @@ enum eHudComponent enum class eHudComponentProperty { FILL_COLOR, - FILL_COLOR_SECOND, + FILL_COLOR_SECONDARY, DRAW_BLACK_BORDER, DRAW_PERCENTAGE, BLINKING_HP_VALUE, @@ -114,7 +114,7 @@ class CHud virtual CVector2D GetComponentSize(const eHudComponent& component) const noexcept = 0; virtual SColor GetComponentColor(const eHudComponent& component) const noexcept = 0; - virtual SColor GetComponentSecondColor(const eHudComponent& component) const noexcept = 0; + virtual SColor GetComponentSecondaryColor(const eHudComponent& component) const noexcept = 0; virtual SColor GetComponentFontDropColor(const eHudComponent& component) const = 0; virtual bool GetComponentDrawBlackBorder(const eHudComponent& component) const noexcept = 0; diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaBitDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaBitDefs.cpp index f5a9770687..daae2263d4 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaBitDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaBitDefs.cpp @@ -12,8 +12,6 @@ #include "CLuaBitDefs.h" #include "CScriptArgReader.h" -#define mask(n) ((1 << (n)) - 1) - void CLuaBitDefs::LoadFunctions() { constexpr static const std::pair functions[]{ @@ -352,7 +350,7 @@ int CLuaBitDefs::bitExtract(lua_State* luaVM) if (!argStream.HasErrors()) { - lua_pushnumber(luaVM, (uiVar >> iField) & mask(iWidth)); + lua_pushnumber(luaVM, (uiVar >> iField) & BYTE_MASK(iWidth)); return 1; } } @@ -391,7 +389,7 @@ int CLuaBitDefs::bitReplace(lua_State* luaVM) if (!argStream.HasErrors()) { - int iMask = mask(iWidth); + int iMask = BYTE_MASK(iWidth); // Erase bits outside given width uiReplaceValue &= iMask; diff --git a/Shared/sdk/SharedUtil.Defines.h b/Shared/sdk/SharedUtil.Defines.h index bccd2e8f2f..ad4fd126df 100644 --- a/Shared/sdk/SharedUtil.Defines.h +++ b/Shared/sdk/SharedUtil.Defines.h @@ -166,7 +166,7 @@ #define ZERO_POD_STRUCT(ptr) \ memset ( ptr, 0, sizeof(*(ptr)) ) -#define mask(n) ((1 << (n)) - 1) +#define BYTE_MASK(n) ((1 << (n)) - 1) // printf/wprintf helpers // diff --git a/Shared/sdk/SharedUtil.Misc.h b/Shared/sdk/SharedUtil.Misc.h index bd8f7bfe15..55643f126b 100644 --- a/Shared/sdk/SharedUtil.Misc.h +++ b/Shared/sdk/SharedUtil.Misc.h @@ -555,10 +555,10 @@ namespace SharedUtil inline SColor TOCOLOR2SCOLOR(std::uint32_t colorValue) { SColor color; - color.R = static_cast((colorValue >> 16) & mask(8)); - color.G = static_cast((colorValue >> 8) & mask(8)); - color.B = static_cast((colorValue >> 0) & mask(8)); - color.A = static_cast((colorValue >> 24) & mask(8)); + color.R = static_cast((colorValue >> 16) & BYTE_MASK(8)); + color.G = static_cast((colorValue >> 8) & BYTE_MASK(8)); + color.B = static_cast((colorValue >> 0) & BYTE_MASK(8)); + color.A = static_cast((colorValue >> 24) & BYTE_MASK(8)); return color; }