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; };