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 new file mode 100644 index 0000000000..d9a724285c --- /dev/null +++ b/Client/game_sa/CFontSA.cpp @@ -0,0 +1,183 @@ +/***************************************************************************** + * + * 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))0x718A10)(x, y, character); +} + +void CFontSA::PrintString(float x, float y, const char* text) +{ + // Call CFont::PrintString + ((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*))0x71A820)(x, y, text); +} + +void CFontSA::SetScale(float w, float h) +{ + // Call CFont::SetScale + ((void(__cdecl*)(float, float))0x719380)(w, h); +} + +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))0x7193A0)(w, h); +} + +void CFontSA::SetSlantRefPoint(float x, float y) +{ + // Call CFont::SetSlantRefPoint + ((void(__cdecl*)(float, float))0x719400)(x, y); +} + +void CFontSA::SetSlant(float slant) +{ + // Call CFont::SetSlant + ((void(__cdecl*)(float))0x719420)(slant); +} + +void CFontSA::SetColor(const RwColor& color) +{ + // Call CFont::SetColor + ((void(__cdecl*)(RwColor))0x719430)(color); +} + +void CFontSA::SetDropColor(const RwColor& color) +{ + // Call CFont::SetDropColor + ((void(__cdecl*)(RwColor))0x719510)(color); +} + +void CFontSA::SetFontStyle(const eFontStyle& style) +{ + // Call CFont::SetFontStyle + ((void(__cdecl*)(eFontStyle))0x719490)(style); +} + +void CFontSA::SetWrapX(float wrapx) +{ + // Call CFont::SetWrapx + ((void(__cdecl*)(float))0x7194D0)(wrapx); +} + +void CFontSA::SetRightJustifyWrap(float wrap) +{ + // Call CFont::SetRightJustifyWrap + ((void(__cdecl*)(float))0x7194F0)(wrap); +} + +void CFontSA::SetCentreSize(float size) +{ + // Call CFont::SetCentreSize + ((void(__cdecl*)(float))0x7194E0)(size); +} + +void CFontSA::SetDropShadowPosition(std::int16_t offset) +{ + // Call CFont::SetDropShadowPosition + ((void(__cdecl*)(std::int16_t))0x719570)(offset); +} + +void CFontSA::SetEdge(std::int16_t edgeSize) +{ + // Call CFont::SetEdge + ((void(__cdecl*)(std::int16_t))0x719590)(edgeSize); +} + +void CFontSA::SetProportional(bool enable) +{ + // Call CFont::SetProportional + ((void(__cdecl*)(bool))0x7195B0)(enable); +} + +void CFontSA::SetBackground(bool enable, bool includeWrap) +{ + // Call CFont::SetBackground + ((void(__cdecl*)(bool, bool))0x7195C0)(enable, includeWrap); +} + +void CFontSA::SetBackgroundColor(const RwColor& color) +{ + // Call CFont::SetBackgroundColor + ((void(__cdecl*)(RwColor))0x7195E0)(color); +} + +void CFontSA::SetJustify(bool enable) +{ + // Call CFont::SetJustify + ((void(__cdecl*)(bool))0x719600)(enable); +} + +void CFontSA::SetOrientation(const eFontAlignment& alignment) +{ + // Call CFont::SetOrientation + ((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))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*))0x71A5E0)(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); + 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..2d724be8bf --- /dev/null +++ b/Client/game_sa/CFontSA.h @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * 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 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 SetScaleForCurrentLanguage(float w, float h); + + 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 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); } + + 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 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/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 77c78333f3..bfd7341328 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -244,6 +244,7 @@ CGameSA::CGameSA() D3DResourceSystemSA::StaticSetHooks(); CVehicleSA::StaticSetHooks(); CCheckpointSA::StaticSetHooks(); + CHudSA::StaticSetHooks(); } catch (const std::bad_alloc& e) { diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index 2133d7d9a5..4fc3d6f08a 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() 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 6b9c2ff770..887f39eb89 100644 --- a/Client/game_sa/CHudSA.cpp +++ b/Client/game_sa/CHudSA.cpp @@ -15,12 +15,43 @@ #include "CCameraSA.h" #include "CPlayerInfoSA.h" #include "TaskAttackSA.h" +#include "CAERadioTrackManagerSA.h" 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; +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_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}}, + {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() { InitComponentList(); @@ -33,6 +64,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 +73,19 @@ CHudSA::CHudSA() MemPut(0x53E41A + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x53E488 + 2, (DWORD)&m_fSniperCrosshairScale); MemPut(0x53E4BF + 2, (DWORD)&m_fSniperCrosshairScale); + + // 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); + 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) @@ -69,9 +115,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 +196,67 @@ bool CHudSA::IsComponentVisible(eHudComponent component) return false; } +void CHudSA::UpdateStreetchCalculations() +{ + calcStreetchX = rsGlobal->maximumWidth * (*reinterpret_cast(VAR_AspectRatioMultX)); + calcStreetchY = rsGlobal->maximumHeight * (*m_pfAspectRatioMultiplicator); + + SComponentPlacement& hpPlacement = componentProperties.hpBar.placement; + hpPlacement.height = calcStreetchY * 9.0f; + hpPlacement.width = calcStreetchX * 109.0f; + hpPlacement.setDefaultXY = false; + + SComponentPlacement& breathPlacement = componentProperties.breathBar.placement; + breathPlacement.height = calcStreetchY * 9.0f; + breathPlacement.width = calcStreetchX * 62.0f; + breathPlacement.setDefaultXY = false; + + 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; + + 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; +} + // // CHudSA::AdjustComponents // @@ -165,6 +272,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 +285,8 @@ void CHudSA::ResetComponentAdjustment() MemPut(m_pfAspectRatioMultiplicator, 0.002232143f); MemPut(m_pfCameraCrosshairScale, 192.0f); m_fSniperCrosshairScale = 210.0f; + + UpdateStreetchCalculations(); } bool CHudSA::IsCrosshairVisible() @@ -228,3 +339,605 @@ bool CHudSA::IsCrosshairVisible() std::uint8_t crossHairType = *reinterpret_cast(VAR_CTheScripts_bDrawCrossHair); return specialAiming || simpleAiming || crossHairType > 0; } + +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: + case HUD_WANTED: + return true; + } + + 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) + { + 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}; + } +} + +void CHudSA::SetComponentPlacementPosition(SComponentPlacement& placement, const CVector2D& position) noexcept +{ + placement.customX = position.fX; + placement.customY = position.fY; + placement.useCustomPosition = true; +} + +void CHudSA::SetComponentPlacementSize(SComponentPlacement& placement, const CVector2D& size) noexcept +{ + placement.customWidth = size.fX; + placement.customHeight = size.fY; + placement.useCustomSize = true; +} + +void CHudSA::ResetComponent(SComponentPlacement& 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::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; + + 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; + 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 +{ + if (component == HUD_ALL) + { + for (const auto& cmp : m_HudComponentMap) + { + if (cmp.first == HUD_ALL) + continue; + + ResetComponentPlacement(cmp.first, resetSize); + } + + 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) + compRef.fillColor = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; + else + compRef.fillColorSecondary = RwColor{newColor.R, newColor.G, newColor.B, newColor.A}; +} + +void CHudSA::ResetComponentColor(const eHudComponent& component, bool secondColor) noexcept +{ + auto& componentData = GetHudComponentRef(component); + if (!MapFind(defaultComponentProperties, component)) + return; + + const auto& defaultRef = MapGet(defaultComponentProperties, component); + + if (!secondColor) + componentData.fillColor = defaultRef.fillColor; + else + componentData.fillColorSecondary = defaultRef.fillColorSecondary; +} + +void CHudSA::SetComponentFontDropColor(const eHudComponent& component, std::uint32_t color) noexcept +{ + SColor newColor = TOCOLOR2SCOLOR(color); + 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::GetComponentSecondaryColor(const eHudComponent& component) const noexcept +{ + const auto& ref = GetHudComponentRef(component); + return SColorRGBA(ref.fillColorSecondary.r, ref.fillColorSecondary.g, ref.fillColorSecondary.b, ref.fillColorSecondary.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 + bool isValidFrame = (pGame->GetSystemFrameCounter() & 8) == 0; + if (*itemToFlash == 4 && isValidFrame) // 4 = HEALTH_BAR + return; + + CPed* playerPed = pGame->GetPedContext(); + if (!playerPed || (playerPed->GetHealth() <= blinkingBarHPValue && isValidFrame)) + return; + + // Save default position once + if (!componentProperties.hpBar.placement.setDefaultXY) + { + 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.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 = (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 + 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) +{ + // 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.placement.setDefaultXY) + { + 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.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 + 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) +{ + // 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.placement.setDefaultXY) + { + componentProperties.armorBar.placement.x = x; + componentProperties.armorBar.placement.y = y; + componentProperties.armorBar.placement.setDefaultXY = true; + } + + // Use custom position/size? + 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 + 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, bool drawFromBottom, bool scaleForLanguage) +{ + // Use custom position/size? + bool useCustomPosition = properties.placement.useCustomPosition; + bool useCustomSize = properties.placement.useCustomSize; + + 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); + + CFontSA::SetOrientation(properties.alignment); + CFontSA::SetFontStyle(properties.style); + + 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.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.fillColorSecondary : 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; + + if (!drawFromBottom) + CFontSA::PrintString(posX, posY, text); + else + CFontSA::PrintStringFromBottom(posX, posY, 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); +} + +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.fillColorSecondary.r; + color->g = properties.fillColorSecondary.g; + color->b = properties.fillColorSecondary.b; + + if (properties.useCustomAlpha) + color->a = properties.fillColorSecondary.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 std::uintptr_t CONTINUE_RenderWanted = 0x58DFD8; +static void _declspec(naked) HOOK_RenderWanted() +{ + _asm + { + cmp ebp, edi + jle empty + + push 0 + jmp render + + empty: + push 1 + + render: + call CHudSA::RenderWanted + add esp,4 + + jmp CONTINUE_RenderWanted + } +} + +static void HOOK_RenderHudBar(int playerId, int x, int y) +{ + 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() +{ + 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); + 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, &HOOK_RenderWanted); +} diff --git a/Client/game_sa/CHudSA.h b/Client/game_sa/CHudSA.h index 11f1747b51..479d60a82b 100644 --- a/Client/game_sa/CHudSA.h +++ b/Client/game_sa/CHudSA.h @@ -13,19 +13,27 @@ #include #include +#include +#include "CFontSA.h" +#include "CRect.h" #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 +44,16 @@ #define FUNC_DrawWantedLevel 0x58D9A0 #define FUNC_DrawCrosshair 0x58E020 +#define FUNC_CStats_GetFatAndMuscleModifier 0x559AF0 +#define FUNC_CSprite2d_DrawBarChart 0x728640 +#define FUNC_CSprie2d_Draw 0x728350 +#define FUNC_CSprite_RenderOneXLUSprite 0x70D000 + #define CODE_ShowMoney 0x58F47D #define VAR_CTheScripts_bDrawCrossHair 0xA44490 +#define VAR_RSGlobal 0xC17040 +#define VAR_ItemToFlash 0xBAB1DC struct SHudComponent { @@ -51,6 +66,114 @@ 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 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}; + float customWidth{0.0f}, customHeight{0.0f}; + + bool useCustomPosition{false}; + bool useCustomSize{false}; + bool setDefaultXY{false}; +}; + +struct SHudComponentData +{ + SComponentPlacement placement{}; + RwColor fillColor{}; + RwColor fillColorSecondary{0,0,0,255}; + + // Bar + bool drawBlackBorder{true}; + bool drawPercentage{false}; + + // Text + 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 = {}, + RwColor fillSecondary = {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, + bool useCustomAlpha = false) : fillColor(fill), + fillColorSecondary(fillSecondary), + drawBlackBorder(blackBorder), + drawPercentage(percentage), + dropColor(drop), + alignment(align), + style(fontStyle), + textOutline(outline), + textShadow(shadow), + proportional(prop), + useCustomAlpha(useCustomAlpha) {} +}; + +struct ComponentProperties +{ + SHudComponentData hpBar; + SHudComponentData breathBar; + SHudComponentData armorBar; + + SHudComponentData clock; + SHudComponentData money; + SHudComponentData ammo; + SHudComponentData vehName; + SHudComponentData areaName; + SHudComponentData radioName; + + SHudComponentData weaponIcon; + SHudComponentData wanted; +}; + class CHudSA : public CHud { public: @@ -63,12 +186,101 @@ class CHudSA : public CHud void ResetComponentAdjustment(); bool IsCrosshairVisible(); -protected: + 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 { 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; + + 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 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 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; } + 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; } + + CVector2D GetComponentTextSize(const eHudComponent& component) const override; + + static RsGlobal* GetRSGlobal() noexcept { return rsGlobal; } + static RwColor GetHUDColour(const eHudColour& colour) noexcept; + + 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(); + 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 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; float* m_pfAspectRatioMultiplicator; float* m_pfCameraCrosshairScale; float m_fSniperCrosshairScale; + + static RsGlobal* rsGlobal; + static std::int16_t* itemToFlash; + + static float calcStreetchX; + static float calcStreetchY; + static float blinkingBarHPValue; }; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 5eb12b9970..1c9e4ed4bf 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -1761,6 +1761,24 @@ void CModelInfoSA::MakeObjectModel(ushort usBaseID) CopyStreamingInfoFromModel(usBaseID); } +void CModelInfoSA::MakeObjectDamageableModel(std::uint16_t baseModel) +{ + CDamageableModelInfoSAInterface* m_pInterface = new CDamageableModelInfoSAInterface(); + + CDamageableModelInfoSAInterface* pBaseObjectInfo = static_cast(ppModelInfo[baseModel]); + MemCpyFast(m_pInterface, pBaseObjectInfo, sizeof(CDamageableModelInfoSAInterface)); + m_pInterface->usNumberOfRefs = 0; + m_pInterface->pRwObject = nullptr; + m_pInterface->usUnknown = 65535; + m_pInterface->usDynamicIndex = 65535; + m_pInterface->m_damagedAtomic = nullptr; + + ppModelInfo[m_dwModelID] = m_pInterface; + + m_dwParentID = baseModel; + CopyStreamingInfoFromModel(baseModel); +} + void CModelInfoSA::MakeTimedObjectModel(ushort usBaseID) { CTimeModelInfoSAInterface* m_pInterface = new CTimeModelInfoSAInterface(); @@ -1826,7 +1844,14 @@ void CModelInfoSA::DeallocateModel(void) delete reinterpret_cast(ppModelInfo[m_dwModelID]); break; case eModelInfoType::ATOMIC: - delete reinterpret_cast(ppModelInfo[m_dwModelID]); + if (IsDamageableAtomic()) + { + delete reinterpret_cast(ppModelInfo[m_dwModelID]); + } + else + { + delete reinterpret_cast(ppModelInfo[m_dwModelID]); + } break; case eModelInfoType::CLUMP: delete reinterpret_cast(ppModelInfo[m_dwModelID]); @@ -2081,6 +2106,12 @@ bool CModelInfoSA::IsTowableBy(CModelInfo* towingModel) return isTowable; } +bool CModelInfoSA::IsDamageableAtomic() +{ + void* asDamagable = ((void* (*)())m_pInterface->VFTBL->AsDamageAtomicModelInfoPtr)(); + return asDamagable != nullptr; +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CModelInfoSA::ForceUnload diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index 50d0f5dce8..6d0e00c758 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -268,6 +268,12 @@ class CVehicleModelUpgradePosnDesc }; static_assert(sizeof(CVehicleModelUpgradePosnDesc) == 0x20, "Invalid size of CVehicleModelUpgradePosnDesc class"); +class CDamageableModelInfoSAInterface : public CBaseModelInfoSAInterface +{ +public: + void* m_damagedAtomic; +}; + class CVehicleModelVisualInfoSAInterface // Not sure about this name. If somebody knows more, please change { public: @@ -466,6 +472,7 @@ class CModelInfoSA : public CModelInfo // CModelInfoSA methods void MakePedModel(char* szTexture); void MakeObjectModel(ushort usBaseModelID); + void MakeObjectDamageableModel(std::uint16_t usBaseModelID) override; void MakeVehicleAutomobile(ushort usBaseModelID); void MakeTimedObjectModel(ushort usBaseModelID); void MakeClumpModel(ushort usBaseModelID); @@ -486,6 +493,7 @@ class CModelInfoSA : public CModelInfo bool IsTowableBy(CModelInfo* towingModel) override; bool IsDynamic() { return m_pInterface ? m_pInterface->usDynamicIndex != MODEL_PROPERTIES_GROUP_STATIC : false; }; + bool IsDamageableAtomic() override; static bool IsVehicleModel(std::uint32_t model) noexcept; diff --git a/Client/game_sa/CPlayerInfoSA.h b/Client/game_sa/CPlayerInfoSA.h index fd73385f05..108864c5f8 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() 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/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 99eb78de34..b52270e22c 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(); @@ -4401,12 +4404,9 @@ bool CClientGame::ApplyPedDamageFromGame(eWeaponType weaponUsed, float fDamage, return false; } - if (pDamagedPed->IsLocalPlayer()) - { - // Reget values in case they have been changed during onClientPlayerDamage event (Avoid AC#1 kick) - fCurrentHealth = pDamagedPed->GetGamePlayer()->GetHealth(); - fCurrentArmor = pDamagedPed->GetGamePlayer()->GetArmor(); - } + // Reget values in case they have been changed during onClientPlayerDamage/onClientPedDamage event (Avoid AC#1 kick) + fCurrentHealth = pDamagedPed->GetGamePlayer()->GetHealth(); + fCurrentArmor = pDamagedPed->GetGamePlayer()->GetArmor(); bool bIsBeingShotWhilstAiming = (weaponUsed >= WEAPONTYPE_PISTOL && weaponUsed <= WEAPONTYPE_MINIGUN && pDamagedPed->IsUsingGun()); bool bOldBehaviour = !IsGlitchEnabled(GLITCH_HITANIM); diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index fd1e6e4ab5..906f77324c 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -51,6 +51,17 @@ bool CClientModel::Allocate(ushort usParentID) return true; } break; + case eClientModelType::OBJECT_DAMAGEABLE: + { + bool isValidModel = g_pClientGame->GetObjectManager()->IsValidModel(usParentID); + bool isDamagable = pParentModelInfo->IsDamageableAtomic(); + if (isValidModel && isDamagable) + { + pModelInfo->MakeObjectDamageableModel(usParentID); + return true; + } + break; + } case eClientModelType::CLUMP: if (g_pClientGame->GetObjectManager()->IsValidModel(usParentID)) { @@ -109,6 +120,7 @@ void CClientModel::RestoreEntitiesUsingThisModel() { case eClientModelType::PED: case eClientModelType::OBJECT: + case eClientModelType::OBJECT_DAMAGEABLE: case eClientModelType::CLUMP: case eClientModelType::TIMED_OBJECT: case eClientModelType::VEHICLE: @@ -174,6 +186,7 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) } case eClientModelType::CLUMP: case eClientModelType::OBJECT: + case eClientModelType::OBJECT_DAMAGEABLE: case eClientModelType::TIMED_OBJECT: { const auto& objects = &g_pClientGame->GetManager()->GetObjectManager()->GetObjects(); diff --git a/Client/mods/deathmatch/logic/CClientModel.h b/Client/mods/deathmatch/logic/CClientModel.h index 903148192d..759890e0e5 100644 --- a/Client/mods/deathmatch/logic/CClientModel.h +++ b/Client/mods/deathmatch/logic/CClientModel.h @@ -18,6 +18,7 @@ enum class eClientModelType { PED, OBJECT, + OBJECT_DAMAGEABLE, VEHICLE, TIMED_OBJECT, CLUMP, diff --git a/Client/mods/deathmatch/logic/CClientPad.cpp b/Client/mods/deathmatch/logic/CClientPad.cpp index 2f68b90baf..223028a0c7 100644 --- a/Client/mods/deathmatch/logic/CClientPad.cpp +++ b/Client/mods/deathmatch/logic/CClientPad.cpp @@ -116,13 +116,6 @@ CClientPad::CClientPad() { m_fStates[i] = 0.0f; } - - // Initialise our analog control states - for (unsigned int i = 0; i < MAX_GTA_ANALOG_CONTROLS; i++) - { - m_sScriptedStates[i] = CS_NAN; - m_bScriptedStatesNextFrameOverride[i] = false; - } } bool CClientPad::GetControlState(const char* szName, bool& bState) @@ -468,6 +461,16 @@ bool CClientPad::GetAnalogControlIndex(const char* szName, unsigned int& uiIndex return false; } +void CClientPad::InitAnalogControlStates() +{ + // Initialise our analog control states + for (unsigned int i = 0; i < MAX_GTA_ANALOG_CONTROLS; i++) + { + m_sScriptedStates[i] = CS_NAN; + m_bScriptedStatesNextFrameOverride[i] = false; + } +} + // Get the analog control state directly from a pad state. Use for players. bool CClientPad::GetAnalogControlState(const char* szName, CControllerState& cs, bool bOnFoot, float& fState, bool bIgnoreOverrides) { diff --git a/Client/mods/deathmatch/logic/CClientPad.h b/Client/mods/deathmatch/logic/CClientPad.h index db6bac04e0..348fe5a29b 100644 --- a/Client/mods/deathmatch/logic/CClientPad.h +++ b/Client/mods/deathmatch/logic/CClientPad.h @@ -23,6 +23,7 @@ class CClientPad static const char* GetControlName(unsigned int uiIndex); static bool GetAnalogControlIndex(const char* szName, unsigned int& uiIndex); + static void InitAnalogControlStates(); CClientPad(); diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index c3d2f27f91..adf37d0224 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -251,6 +251,9 @@ void CClientPed::Init(CClientManager* pManager, unsigned long ulModelID, bool bI // Init the local player _CreateLocalModel(); + // Init default analog control states + CClientPad::InitAnalogControlStates(); + // Give full health, no armor, no weapons and put him at a safe location SetHealth(GetMaxHealth()); SetArmor(0); @@ -2705,6 +2708,10 @@ void CClientPed::StreamedInPulse(bool bDoStandardPulses) return; } + // Re-create ped + if (m_shouldRecreate) + ReCreateGameEntity(); + // Grab some vars here, saves getting them twice CClientVehicle* pVehicle = GetOccupiedVehicle(); @@ -3974,11 +3981,7 @@ void CClientPed::_ChangeModel() { // ChrML: Changing the skin in certain cases causes player sliding. So we recreate instead. - // Kill the old player - _DestroyModel(); - - // Create the new with the new skin - _CreateModel(); + m_shouldRecreate = true; } // ReAttach satchels @@ -4012,11 +4015,7 @@ void CClientPed::ReCreateModel() m_pLoadedModelInfo->ModelAddRef(BLOCKING, "CClientPed::ReCreateModel"); } - // Destroy the old model - _DestroyModel(); - - // Create the new model - _CreateModel(); + m_shouldRecreate = true; // Remove the reference we temporarily added again if (bSameModel) @@ -4026,6 +4025,20 @@ void CClientPed::ReCreateModel() } } +void CClientPed::ReCreateGameEntity() +{ + if (!m_shouldRecreate || !m_pPlayerPed) + return; + + // Destroy current game entity + _DestroyModel(); + + // Create the new game entity + _CreateModel(); + + m_shouldRecreate = false; +} + void CClientPed::ModelRequestCallback(CModelInfo* pModelInfo) { // If we have a player loaded diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index 5c7b2cb4a6..2934990e05 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -566,6 +566,7 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule // Used to destroy the current game ped and create a new one in the same state. void ReCreateModel(); + void ReCreateGameEntity(); void _CreateModel(); void _CreateLocalModel(); @@ -725,6 +726,7 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule bool m_bPendingRebuildPlayer; uint m_uiFrameLastRebuildPlayer; bool m_bIsSyncing; + bool m_shouldRecreate{false}; bool m_bBulletImpactData; CClientEntityPtr m_pBulletImpactEntity; diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 6fc425fa83..4274befdc8 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -111,6 +111,38 @@ 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::FILL_COLOR_SECONDARY, "fillColorSecondary") +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::CUSTOM_ALPHA, "useCustomAlpha") +ADD_ENUM(eHudComponentProperty::TEXT_SIZE, "textSize") +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") @@ -675,6 +707,7 @@ IMPLEMENT_ENUM_END("surface-adhesion-group") IMPLEMENT_ENUM_CLASS_BEGIN(eClientModelType) ADD_ENUM(eClientModelType::PED, "ped") ADD_ENUM(eClientModelType::OBJECT, "object") +ADD_ENUM(eClientModelType::OBJECT_DAMAGEABLE, "object-damageable") ADD_ENUM(eClientModelType::VEHICLE, "vehicle") ADD_ENUM(eClientModelType::TIMED_OBJECT, "timed-object") ADD_ENUM(eClientModelType::CLUMP, "clump") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 818ebeb308..4fbb4fd53f 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -111,6 +111,9 @@ enum eDXVerticalAlign 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/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 7ca02230d5..a6a688c366 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -892,6 +892,9 @@ int CLuaEngineDefs::EngineRequestModel(lua_State* luaVM) case eClientModelType::OBJECT: usParentID = 1337; // BinNt07_LA (trash can) break; + case eClientModelType::OBJECT_DAMAGEABLE: + usParentID = 994; // lhouse_barrier2 + break; case eClientModelType::VEHICLE: usParentID = VT_LANDSTAL; break; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.cpp index e276a3ddf7..4702e9ce3d 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}, @@ -51,6 +53,7 @@ void CLuaPlayerDefs::LoadFunctions() {"isPlayerMapVisible", IsPlayerMapVisible}, {"getPlayerMapBoundingBox", GetPlayerMapBoundingBox}, {"getPlayerMapOpacity", ArgumentParser}, + {"getPlayerHudComponentProperty", ArgumentParser}, }; // Add functions @@ -77,6 +80,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"); @@ -90,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"); @@ -644,3 +650,402 @@ bool CLuaPlayerDefs::IsPlayerCrosshairVisible() { return g_pGame->GetHud()->IsCrosshairVisible(); } + +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) + { + case eHudComponentProperty::POSITION: + { + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentPosition(component, std::get(value)); + return true; + } + case eHudComponentProperty::SIZE: + { + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentSize(component, std::get(value)); + return true; + } + case eHudComponentProperty::FILL_COLOR: + case eHudComponentProperty::FILL_COLOR_SECONDARY: + { + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentColor(component, static_cast(std::get(value)), property == eHudComponentProperty::FILL_COLOR_SECONDARY); + return true; + } + case eHudComponentProperty::DRAW_BLACK_BORDER: + { + if (!hud->IsComponentBar(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentDrawBlackBorder(component, std::get(value)); + return true; + } + case eHudComponentProperty::DRAW_PERCENTAGE: + { + if (!hud->IsComponentBar(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + hud->SetComponentDrawPercentage(component, std::get(value)); + return true; + } + case eHudComponentProperty::BLINKING_HP_VALUE: + { + if (component != HUD_HEALTH) + return false; + + if (!std::holds_alternative(value)) + return false; + + 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; + if (!StringToEnum(std::get(value), val)) + return false; + + // 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: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + eFontAlignment val; + if (!StringToEnum(std::get(value), val)) + return false; + + // 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: + { + if (!hud->IsComponentText(component)) + return false; + + if (!std::holds_alternative(value)) + return false; + + 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) 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 (std::size_t 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_SECONDARY: + { + if (!hud->IsComponentBar(component) && !hud->IsComponentText(component) && component != HUD_WEAPON) + return false; + + bool second = property == eHudComponentProperty::FILL_COLOR_SECONDARY; + if (second && (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON)) + return false; + + hud->ResetComponentColor(component, second); + return true; + } + case eHudComponentProperty::DROP_COLOR: + { + if (!hud->IsComponentText(component)) + return false; + + hud->SetComponentFontDropColor(component, COLOR_RGBA(0, 0, 0, 255)); + return true; + } + case eHudComponentProperty::DRAW_BLACK_BORDER: + { + if (!hud->IsComponentBar(component)) + return false; + + hud->SetComponentDrawBlackBorder(component, true); + return true; + } + case eHudComponentProperty::DRAW_PERCENTAGE: + { + if (!hud->IsComponentBar(component)) + return false; + + hud->SetComponentDrawPercentage(component, false); + return true; + } + case eHudComponentProperty::BLINKING_HP_VALUE: + { + 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; + + 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; + } + 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_SECONDARY: + { + if (component != HUD_RADIO && component != HUD_MONEY && component != HUD_WANTED && component != HUD_WEAPON) + return false; + + SColor& color = hud->GetComponentSecondaryColor(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); + case eHudComponentProperty::TEXT_SIZE: + { + CVector2D& size = hud->GetComponentTextSize(component); + return CLuaMultiReturn{size.fX, size.fY}; + } + } + + return false; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaPlayerDefs.h index 1a2895ed3d..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,6 +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) 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/CGame.h b/Client/sdk/game/CGame.h index 51f94c9d77..60901293f7 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() 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 af37d4a4cd..403a0e73fb 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,42 @@ enum eHudComponent HUD_HELP_TEXT, }; +enum class eHudComponentProperty +{ + FILL_COLOR, + FILL_COLOR_SECONDARY, + DRAW_BLACK_BORDER, + DRAW_PERCENTAGE, + BLINKING_HP_VALUE, + POSITION, + SIZE, + DROP_COLOR, + TEXT_OUTLINE, + TEXT_SHADOW, + TEXT_STYLE, + TEXT_ALIGNMENT, + TEXT_PROPORTIONAL, + CUSTOM_ALPHA, + TEXT_SIZE, + + ALL_PROPERTIES, +}; + +enum class eFontStyle : std::uint8_t +{ + FONT_GOTHIC, + FONT_SUBTITLES, + FONT_MENU, + FONT_PRICEDOWN, +}; + +enum class eFontAlignment : std::uint8_t +{ + ALIGN_CENTER, + ALIGN_LEFT, + ALIGN_RIGHT, +}; + class CHud { public: @@ -42,4 +79,55 @@ class CHud virtual void AdjustComponents(float fAspectRatio) = 0; virtual void ResetComponentAdjustment() = 0; virtual bool IsCrosshairVisible() = 0; + + // Hud properties + 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 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 GetComponentSecondaryColor(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; + + virtual CVector2D GetComponentTextSize(const eHudComponent& component) const = 0; }; diff --git a/Client/sdk/game/CModelInfo.h b/Client/sdk/game/CModelInfo.h index c578be1990..8b27fc0304 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -236,6 +236,7 @@ class CModelInfo virtual RwObject* GetRwObject() = 0; virtual void MakePedModel(char* szTexture) = 0; virtual void MakeObjectModel(unsigned short usBaseID) = 0; + virtual void MakeObjectDamageableModel(std::uint16_t baseID) = 0; virtual void MakeVehicleAutomobile(unsigned short usBaseID) = 0; virtual void MakeTimedObjectModel(unsigned short usBaseID) = 0; virtual void MakeClumpModel(unsigned short usBaseID) = 0; @@ -252,4 +253,5 @@ class CModelInfo virtual unsigned int GetParentID() = 0; virtual bool IsDynamic() = 0; + virtual bool IsDamageableAtomic() = 0; }; diff --git a/Client/sdk/game/CPlayerInfo.h b/Client/sdk/game/CPlayerInfo.h index 91b7e16d6c..93a87c4c9e 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() const = 0; + virtual std::uint8_t GetMaxArmor() const = 0; }; diff --git a/Server/mods/deathmatch/editor.conf b/Server/mods/deathmatch/editor.conf index 1355e673ee..1a9b16041e 100644 --- a/Server/mods/deathmatch/editor.conf +++ b/Server/mods/deathmatch/editor.conf @@ -3,6 +3,28 @@ Map Editor Server + + + + + + + + + + + + + + + + + + + + + Default MTA Server + + + + + + + + + + + + + + + + + + + + + Default MTA Server - + + + + + + + + + + + + + + + + + + + + + + Default MTA Server + + + + + + + + + + + + + + + + + + + + +