From 942c4f9c21d16431832d4451e8243b2307b96dc8 Mon Sep 17 00:00:00 2001 From: FileEX Date: Wed, 2 Oct 2024 22:38:50 +0200 Subject: [PATCH] Roadsign support --- Client/game_sa/C2DEffectSA.cpp | 145 +++++++++++++++--- Client/game_sa/C2DEffectSA.h | 21 ++- Client/game_sa/CModelInfoSA.cpp | 30 +++- Client/game_sa/gamesa_renderware.h | 3 +- Client/game_sa/gamesa_renderware.hpp | 1 + .../deathmatch/logic/CClient2DFXManager.cpp | 49 +++--- Client/multiplayer_sa/CMultiplayerSA.cpp | 4 +- Client/sdk/game/C2DEffect.h | 12 +- 8 files changed, 208 insertions(+), 57 deletions(-) diff --git a/Client/game_sa/C2DEffectSA.cpp b/Client/game_sa/C2DEffectSA.cpp index 982dbfb679..7d838e7eaf 100644 --- a/Client/game_sa/C2DEffectSA.cpp +++ b/Client/game_sa/C2DEffectSA.cpp @@ -198,7 +198,10 @@ void C2DEffectSA::SetRoadsignText(const std::string& text, std::uint8_t line) if (IsValidRoadsign()) { if (!m_effectInterface->effect.roadsign.text) + { m_effectInterface->effect.roadsign.text = static_cast(std::malloc(64)); + MemSetFast(m_effectInterface->effect.roadsign.text, 0, 64); + } if (!m_effectInterface->effect.roadsign.text) return; @@ -207,6 +210,32 @@ void C2DEffectSA::SetRoadsignText(const std::string& text, std::uint8_t line) } } +RwV2d& C2DEffectSA::GetRoadsignSize() +{ + if (IsValidRoadsign()) + return m_effectInterface->effect.roadsign.size; + + static RwV2d dummySize{0, 0}; + return dummySize; +} + +RwV3d& C2DEffectSA::GetRoadsignRotation() +{ + if (IsValidRoadsign()) + return m_effectInterface->effect.roadsign.rotation; + + static RwV3d dummyRotation{0, 0, 0}; + return dummyRotation; +} + +std::string C2DEffectSA::GetRoadsignText() const +{ + if (IsValidRoadsign() && m_effectInterface->effect.roadsign.text) + return std::string(m_effectInterface->effect.roadsign.text, 64); + + return ""; +} + void C2DEffectSA::SetEscalatorBottom(const RwV3d& bottom) { if (IsValidEscalator()) @@ -231,6 +260,99 @@ void C2DEffectSA::SetEscalatorDirection(std::uint8_t direction) m_effectInterface->effect.escalator.direction = direction; } +RwV3d& C2DEffectSA::GetEscalatorBottom() +{ + if (IsValidEscalator()) + return m_effectInterface->effect.escalator.bottom; + + static RwV3d dummyBottom{0, 0, 0}; + return dummyBottom; +} + +RwV3d& C2DEffectSA::GetEscalatorTop() +{ + if (IsValidEscalator()) + return m_effectInterface->effect.escalator.top; + + static RwV3d dummyTop{0, 0, 0}; + return dummyTop; +} + +RwV3d& C2DEffectSA::GetEscalatorEnd() +{ + if (IsValidEscalator()) + return m_effectInterface->effect.escalator.end; + + static RwV3d dummyEnd{0, 0, 0}; + return dummyEnd; +} + +RpAtomic* C2DEffectSA::Roadsign_CreateAtomic(const RwV3d& position, const RwV3d& rotation, float sizeX, float sizeY, std::uint32_t numLines, char* line1, char* line2, char* line3, char* line4, std::uint32_t numLetters, std::uint8_t palleteID) +{ + // Call CCustomRoadsignMgr::CreateRoadsignAtomic + RpAtomic* atomic = ((RpAtomic*(__cdecl*)(float, float, std::int32_t, char*, char*, char*, char*, std::int32_t, std::uint8_t))0x6FF2D0)(sizeX, sizeY, numLines, line1, line2, line3, line4, numLetters, palleteID); + RwFrame* frame = RpAtomicGetFrame(atomic); + RwFrameSetIdentity(frame); + + const RwV3d axis0{1.0f, 0.0f, 0.0f}, axis1{0.0f, 1.0f, 0.0f}, axis2{0.0f, 0.0f, 1.0f}; + RwFrameRotate(frame, &axis2, rotation.z, rwCOMBINEREPLACE); + RwFrameRotate(frame, &axis0, rotation.x, rwCOMBINEPOSTCONCAT); + RwFrameRotate(frame, &axis1, rotation.y, rwCOMBINEPOSTCONCAT); + + RwFrameTranslate(frame, &position, TRANSFORM_AFTER); + RwFrameUpdateObjects(frame); + + return atomic; +} + +std::uint32_t C2DEffectSA::Roadsign_GetPalleteIDFromFlags(std::uint8_t flags) +{ + std::uint32_t id = (flags >> 4) & 3; + return id <= 3 ? id : 0; +} + +std::uint32_t C2DEffectSA::Roadsign_GetNumLettersFromFlags(std::uint8_t flags) +{ + std::uint32_t letters = (flags >> 2) & 3; + switch (letters) + { + case 1u: + return 2; + case 2u: + return 4; + case 3u: + return 8; + default: + return 16; + } +} + +std::uint32_t C2DEffectSA::Roadsign_GetNumLinesFromFlags(std::uint8_t flags) +{ + std::uint32_t lines = flags & 3; + return (lines <= 3 && lines > 0) ? lines : 4; +} + +void C2DEffectSA::Roadsign_DestroyAtomic(C2DEffectSAInterface* effect) +{ + if (!effect) + return; + + t2dEffectRoadsign& roadsign = effect->effect.roadsign; + if (roadsign.atomic) + { + RwFrame* frame = RpAtomicGetFrame(roadsign.atomic); + if (frame) + { + RpAtomicSetFrame(roadsign.atomic, nullptr); + RwFrameDestroy(frame); + } + + RpAtomicDestroy(roadsign.atomic); + roadsign.atomic = nullptr; + } +} + C2DEffectSAInterface* C2DEffectSA::CreateCopy(C2DEffectSAInterface* effect) { C2DEffectSAInterface* copy = new C2DEffectSAInterface(); @@ -250,17 +372,16 @@ C2DEffectSAInterface* C2DEffectSA::CreateCopy(C2DEffectSAInterface* effect) copy->effect.roadsign.text = static_cast(std::malloc(64)); if (copy->effect.roadsign.text) { - std::memset(copy->effect.roadsign.text, 0, 64); - std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64); - } + MemSetFast(copy->effect.roadsign.text, 0, 64); + MemCpyFast(copy->effect.roadsign.text, effect->effect.roadsign.text, 64); - copy->effect.roadsign.atomic = RpAtomicClone(effect->effect.roadsign.atomic); + copy->effect.roadsign.atomic = Roadsign_CreateAtomic(copy->position, copy->effect.roadsign.rotation, copy->effect.roadsign.size.x, copy->effect.roadsign.size.y, Roadsign_GetNumLinesFromFlags(copy->effect.roadsign.flags), ©->effect.roadsign.text[0], ©->effect.roadsign.text[16], ©->effect.roadsign.text[32], ©->effect.roadsign.text[48], Roadsign_GetNumLettersFromFlags(copy->effect.roadsign.flags), Roadsign_GetPalleteIDFromFlags(copy->effect.roadsign.flags)); + } } return copy; } -// C2DEffect::Shutdown causes random unknown crash in ntdll.dll so we need own function void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect) { if (!effect) @@ -269,25 +390,13 @@ void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect) if (effect->type == e2dEffectType::ROADSIGN) { t2dEffectRoadsign& roadsign = effect->effect.roadsign; + Roadsign_DestroyAtomic(effect); if (roadsign.text) { std::free(roadsign.text); roadsign.text = nullptr; } - - if (roadsign.atomic) - { - RwFrame* frame = RpAtomicGetFrame(roadsign.atomic); - if (frame) - { - RpAtomicSetFrame(roadsign.atomic, nullptr); - RwFrameDestroy(frame); - } - - RpAtomicDestroy(roadsign.atomic); - roadsign.atomic = nullptr; - } } else if (effect->type == e2dEffectType::LIGHT) { diff --git a/Client/game_sa/C2DEffectSA.h b/Client/game_sa/C2DEffectSA.h index f41f15e834..79a0bd2d37 100644 --- a/Client/game_sa/C2DEffectSA.h +++ b/Client/game_sa/C2DEffectSA.h @@ -41,6 +41,7 @@ class C2DEffectSA : public C2DEffect ~C2DEffectSA() = default; C2DEffectSAInterface* GetInterface() noexcept { return m_effectInterface; } + e2dEffectType GetEffectType() override { return m_effectInterface ? m_effectInterface->type : e2dEffectType::NONE; } bool IsValidLight() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::LIGHT; }; bool IsValidRoadsign() const noexcept { return m_effectInterface && m_effectInterface->type == e2dEffectType::ROADSIGN; } @@ -80,7 +81,7 @@ class C2DEffectSA : public C2DEffect std::uint8_t GetCoronaFlareType() const override { return IsValidLight() ? m_effectInterface->effect.light.coronaFlareType : 0; } std::uint16_t GetLightFlags() const override { return IsValidLight() ? m_effectInterface->effect.light.flags : 0; } std::int8_t GetShadowDistance() const override { return IsValidLight() ? m_effectInterface->effect.light.shadowZDistance : 0; } - CVector GetCoronaOffsets() const override; + CVector GetCoronaOffsets() const override; RwColor GetCoronaColor() const override { return IsValidLight() ? m_effectInterface->effect.light.color : RwColor{0,0,0,0}; } std::string GetCoronaTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.coronaTex ? m_effectInterface->effect.light.coronaTex->name : "") : ""; } std::string GetShadowTexture() const override { return IsValidLight() ? (m_effectInterface->effect.light.shadowTex ? m_effectInterface->effect.light.shadowTex->name : "") : ""; } @@ -100,10 +101,10 @@ class C2DEffectSA : public C2DEffect void SetRoadsignText(const std::string& text, std::uint8_t line) override; // Get - RwV2d GetRoadsignSize() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.size : RwV2d{0,0}; } - RwV3d GetRoadsignRotation() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.rotation : RwV3d{0,0,0}; } + RwV2d& GetRoadsignSize() override; + RwV3d& GetRoadsignRotation() override; std::uint16_t GetRoadsignFlags() const override { return IsValidRoadsign() ? m_effectInterface->effect.roadsign.flags : 0; } - std::string GetRoadsignText() const override { return IsValidRoadsign() ? (m_effectInterface->effect.roadsign.text ? std::string(m_effectInterface->effect.roadsign.text, strnlen(m_effectInterface->effect.roadsign.text, 64)) : "") : ""; } + std::string GetRoadsignText() const override; // Escalator properties // Set @@ -113,12 +114,16 @@ class C2DEffectSA : public C2DEffect void SetEscalatorDirection(std::uint8_t direction) override; // Get - RwV3d GetEscalatorBottom() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.bottom : RwV3d{0, 0, 0}; } - RwV3d GetEscalatorTop() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.top : RwV3d{0, 0, 0}; } - RwV3d GetEscalatorEnd() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.end : RwV3d{0, 0, 0}; } + RwV3d& GetEscalatorBottom() override; + RwV3d& GetEscalatorTop() override; + RwV3d& GetEscalatorEnd() override; std::uint8_t GetEscalatorDirection() const override { return IsValidEscalator() ? m_effectInterface->effect.escalator.direction : 0; } - e2dEffectType GetEffectType() override { return m_effectInterface ? m_effectInterface->type : e2dEffectType::NONE; } + static RpAtomic* Roadsign_CreateAtomic(const RwV3d& position, const RwV3d& rotation, float sizeX, float sizeY, std::uint32_t numLines, char* line1, char* line2, char* line3, char* line4, std::uint32_t numLetters, std::uint8_t palleteID); + static std::uint32_t Roadsign_GetPalleteIDFromFlags(std::uint8_t flags); + static std::uint32_t Roadsign_GetNumLettersFromFlags(std::uint8_t flags); + static std::uint32_t Roadsign_GetNumLinesFromFlags(std::uint8_t flags); + static void Roadsign_DestroyAtomic(C2DEffectSAInterface* effect); static C2DEffectSAInterface* CreateCopy(C2DEffectSAInterface* effect); diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index b35cbe4425..e7a23908e4 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -2157,6 +2157,20 @@ void CModelInfoSA::Update2DFXEffect(C2DEffectSA* effect) // Call Fx_c::CreateEntityFx ((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*, const char*, RwV3d*, RwMatrix*))FUNC_Fx_c_CreateEntityFx)(fx, entity, effectInterface->effect.particle.szName, &effectInterface->position, matrixTransform); } + + break; + } + case e2dEffectType::ROADSIGN: + { + t2dEffectRoadsign& roadsign = effectInterface->effect.roadsign; + C2DEffectSA::Roadsign_DestroyAtomic(effectInterface); + + std::uint32_t numLines = C2DEffectSA::Roadsign_GetNumLinesFromFlags(roadsign.flags); + std::uint32_t numLetters = C2DEffectSA::Roadsign_GetNumLettersFromFlags(roadsign.flags); + std::uint8_t palleteID = C2DEffectSA::Roadsign_GetPalleteIDFromFlags(roadsign.flags); + roadsign.atomic = C2DEffectSA::Roadsign_CreateAtomic(effectInterface->position, roadsign.rotation, roadsign.size.x, roadsign.size.y, numLines, &roadsign.text[0], &roadsign.text[16], &roadsign.text[32], &roadsign.text[48], numLetters, palleteID); + + break; } } } @@ -2301,6 +2315,7 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault) // Prevent creation when stream in but keep in memory so we can restore it later effect->type = e2dEffectType::NONE; + break; } case e2dEffectType::SUN_GLARE: { @@ -2318,8 +2333,11 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault) MapGet(ms_NumOfCustom2DFXEffects, m_pInterface)--; ms_Custom2DFXEffects.erase(it); - delete effect; - effect = nullptr; + if (effect) + { + delete effect; + effect = nullptr; + } } } @@ -2432,8 +2450,14 @@ void CModelInfoSA::RestoreModified2DFXEffects() if (tempVec && (*tempVec)[i]) { MemCpyFast(effectInterface, (*tempVec)[i], sizeof(C2DEffectSAInterface)); - C2DEffectSA::SafeDelete2DFXEffect((*tempVec)[i]); + effectInterface->effect.roadsign.text = static_cast(std::malloc(64)); + if (effectInterface->effect.roadsign.text) + { + MemSetFast(effectInterface->effect.roadsign.text, 0, 64); + MemCpyFast(effectInterface->effect.roadsign.text, (*tempVec)[i]->effect.roadsign.text, 64); + } + C2DEffectSA::SafeDelete2DFXEffect((*tempVec)[i]); Update2DFXEffect(effect); } } diff --git a/Client/game_sa/gamesa_renderware.h b/Client/game_sa/gamesa_renderware.h index 03bffd749b..48a1b2417c 100644 --- a/Client/game_sa/gamesa_renderware.h +++ b/Client/game_sa/gamesa_renderware.h @@ -106,6 +106,7 @@ typedef int(__cdecl* RpHAnimIDGetIndex_t)(RpHAnimHierarchy*, int); typedef RwMatrix*(__cdecl* RpHAnimHierarchyGetMatrixArray_t)(RpHAnimHierarchy*); typedef RtQuat*(__cdecl* RtQuatRotate_t)(RtQuat* quat, const RwV3d* axis, float angle, RwOpCombineType combineOp); typedef RwTexture*(__cdecl* RwReadTexture_t)(const char* name, const char* mask); +typedef RwFrame*(__cdecl* RwFrameRotate_t)(RwFrame* frame, const RwV3d* axis, float angle, RwOpCombineType combine); /*****************************************************************************/ /** Renderware function mappings **/ @@ -197,7 +198,7 @@ RWFUNC(RpHAnimIDGetIndex_t RpHAnimIDGetIndex, (RpHAnimIDGetIndex_t)0xDEAD) RWFUNC(RpHAnimHierarchyGetMatrixArray_t RpHAnimHierarchyGetMatrixArray, (RpHAnimHierarchyGetMatrixArray_t)0xDEAD) RWFUNC(RtQuatRotate_t RtQuatRotate, (RtQuatRotate_t)0xDEAD) RWFUNC(RwReadTexture_t RwReadTexture, reinterpret_cast(0xDEAD)) - +RWFUNC(RwFrameRotate_t RwFrameRotate, reinterpret_cast(0xDEAD)) /*****************************************************************************/ /** GTA function definitions and mappings **/ /*****************************************************************************/ diff --git a/Client/game_sa/gamesa_renderware.hpp b/Client/game_sa/gamesa_renderware.hpp index edabf9a712..a8633cc2ab 100644 --- a/Client/game_sa/gamesa_renderware.hpp +++ b/Client/game_sa/gamesa_renderware.hpp @@ -90,6 +90,7 @@ void InitRwFunctions() RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120; RtQuatRotate = (RtQuatRotate_t)0x7EB7C0; RwReadTexture = reinterpret_cast(0x7F3AC0); + RwFrameRotate = reinterpret_cast(0x7F1010); SetTextureDict = (SetTextureDict_t)0x007319C0; LoadClumpFile = (LoadClumpFile_t)0x005371F0; diff --git a/Client/mods/deathmatch/logic/CClient2DFXManager.cpp b/Client/mods/deathmatch/logic/CClient2DFXManager.cpp index 6fae3e8032..4a17c7265e 100644 --- a/Client/mods/deathmatch/logic/CClient2DFXManager.cpp +++ b/Client/mods/deathmatch/logic/CClient2DFXManager.cpp @@ -108,9 +108,11 @@ effectDataMap CClient2DFXManager::Get2DFXProperties(C2DEffect* effect) const MapSet(properties, "flareType", static_cast(effect->GetCoronaFlareType())); MapSet(properties, "flags", static_cast(effect->GetLightFlags())); MapSet(properties, "shadowDistance", static_cast(effect->GetShadowDistance())); - MapSet(properties, "offsetX", effect->GetCoronaOffsets().fX); - MapSet(properties, "offsetY", effect->GetCoronaOffsets().fY); - MapSet(properties, "offsetZ", effect->GetCoronaOffsets().fZ); + + const CVector& offsets = effect->GetCoronaOffsets(); + MapSet(properties, "offsetX", offsets.fX); + MapSet(properties, "offsetY", offsets.fY); + MapSet(properties, "offsetZ", offsets.fZ); RwColor& color = effect->GetCoronaColor(); int colorValue = (static_cast(color.a) << 24) | (static_cast(color.r) << 16) | (static_cast(color.g) << 8) | static_cast(color.b); @@ -128,11 +130,14 @@ effectDataMap CClient2DFXManager::Get2DFXProperties(C2DEffect* effect) const } case e2dEffectType::ROADSIGN: { - MapSet(properties, "sizeX", effect->GetRoadsignSize().x); - MapSet(properties, "sizeY", effect->GetRoadsignSize().y); - MapSet(properties, "rotX", effect->GetRoadsignRotation().x); - MapSet(properties, "rotY", effect->GetRoadsignRotation().y); - MapSet(properties, "rotZ", effect->GetRoadsignRotation().z); + const RwV2d& size = effect->GetRoadsignSize(); + const RwV3d& rot = effect->GetRoadsignRotation(); + + MapSet(properties, "sizeX", size.x); + MapSet(properties, "sizeY", size.y); + MapSet(properties, "rotX", rot.x); + MapSet(properties, "rotY", rot.y); + MapSet(properties, "rotZ", rot.z); MapSet(properties, "flags", static_cast(effect->GetRoadsignFlags())); MapSet(properties, "text", effect->GetRoadsignText()); @@ -140,15 +145,19 @@ effectDataMap CClient2DFXManager::Get2DFXProperties(C2DEffect* effect) const } case e2dEffectType::ESCALATOR: { - MapSet(properties, "bottomX", effect->GetEscalatorBottom().x); - MapSet(properties, "bottomY", effect->GetEscalatorBottom().y); - MapSet(properties, "bottomZ", effect->GetEscalatorBottom().z); - MapSet(properties, "topX", effect->GetEscalatorTop().x); - MapSet(properties, "topY", effect->GetEscalatorTop().y); - MapSet(properties, "topZ", effect->GetEscalatorTop().z); - MapSet(properties, "endX", effect->GetEscalatorEnd().x); - MapSet(properties, "endY", effect->GetEscalatorEnd().y); - MapSet(properties, "endZ", effect->GetEscalatorEnd().z); + const RwV3d& bottom = effect->GetEscalatorBottom(); + const RwV3d& top = effect->GetEscalatorTop(); + const RwV3d& end = effect->GetEscalatorEnd(); + + MapSet(properties, "bottomX", bottom.x); + MapSet(properties, "bottomY", bottom.y); + MapSet(properties, "bottomZ", bottom.z); + MapSet(properties, "topX", top.x); + MapSet(properties, "topY", top.y); + MapSet(properties, "topZ", top.z); + MapSet(properties, "endX", end.x); + MapSet(properties, "endY", end.y); + MapSet(properties, "endZ", end.z); MapSet(properties, "direction", static_cast(effect->GetEscalatorDirection())); break; @@ -270,7 +279,7 @@ bool CClient2DFXManager::Set2DFXProperty(C2DEffect* effect, const e2dEffectPrope { if (std::holds_alternative(propertyValue)) { - CVector& offsets = effect->GetCoronaOffsets(); + CVector offsets = effect->GetCoronaOffsets(); offsets.fX = static_cast(std::get(propertyValue)); effect->SetCoronaOffsets(offsets); @@ -282,7 +291,7 @@ bool CClient2DFXManager::Set2DFXProperty(C2DEffect* effect, const e2dEffectPrope { if (std::holds_alternative(propertyValue)) { - CVector& offsets = effect->GetCoronaOffsets(); + CVector offsets = effect->GetCoronaOffsets(); offsets.fY = static_cast(std::get(propertyValue)); effect->SetCoronaOffsets(offsets); @@ -294,7 +303,7 @@ bool CClient2DFXManager::Set2DFXProperty(C2DEffect* effect, const e2dEffectPrope { if (std::holds_alternative(propertyValue)) { - CVector& offsets = effect->GetCoronaOffsets(); + CVector offsets = effect->GetCoronaOffsets(); offsets.fZ = static_cast(std::get(propertyValue)); effect->SetCoronaOffsets(offsets); diff --git a/Client/multiplayer_sa/CMultiplayerSA.cpp b/Client/multiplayer_sa/CMultiplayerSA.cpp index 28d5b1f551..63e4429a44 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA.cpp @@ -3018,8 +3018,10 @@ void _declspec(naked) HOOK_CCustomRoadsignMgr__RenderRoadsignAtomic() cmp esi, 0 jz no_render - // original code + // original code with our null check mov eax, dword ptr[esi+4] + test eax, eax + jz no_render fsub [eax+64] mov edx, HOOKPOS_CCustomRoadsignMgr__RenderRoadsignAtomic add edx, 6 diff --git a/Client/sdk/game/C2DEffect.h b/Client/sdk/game/C2DEffect.h index f78614ebaf..c384c198e2 100644 --- a/Client/sdk/game/C2DEffect.h +++ b/Client/sdk/game/C2DEffect.h @@ -54,7 +54,7 @@ class C2DEffect virtual std::uint8_t GetCoronaFlareType() const = 0; virtual std::uint16_t GetLightFlags() const = 0; virtual std::int8_t GetShadowDistance() const = 0; - virtual CVector GetCoronaOffsets() const = 0; + virtual CVector GetCoronaOffsets() const = 0; virtual RwColor GetCoronaColor() const = 0; virtual std::string GetCoronaTexture() const = 0; virtual std::string GetShadowTexture() const = 0; @@ -74,8 +74,8 @@ class C2DEffect virtual void SetRoadsignText(const std::string& text, std::uint8_t line) = 0; // Get - virtual RwV2d GetRoadsignSize() const = 0; - virtual RwV3d GetRoadsignRotation() const = 0; + virtual RwV2d& GetRoadsignSize() = 0; + virtual RwV3d& GetRoadsignRotation() = 0; virtual std::uint16_t GetRoadsignFlags() const = 0; virtual std::string GetRoadsignText() const = 0; @@ -87,9 +87,9 @@ class C2DEffect virtual void SetEscalatorDirection(std::uint8_t direction) = 0; // Get - virtual RwV3d GetEscalatorBottom() const = 0; - virtual RwV3d GetEscalatorTop() const = 0; - virtual RwV3d GetEscalatorEnd() const = 0; + virtual RwV3d& GetEscalatorBottom() = 0; + virtual RwV3d& GetEscalatorTop() = 0; + virtual RwV3d& GetEscalatorEnd() = 0; virtual std::uint8_t GetEscalatorDirection() const = 0; };