From 092495ef5ff8eca311030c9afada0c9cdacb64be Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 6 Sep 2026 19:40:37 +0200 Subject: [PATCH 01/44] reimplement: SHC_3BB0A8C1_0x0045F130 100% --- .../Constructor_TextEditorState.cpp | 42 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp diff --git a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp new file mode 100644 index 0000000000..70d1b72d32 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp @@ -0,0 +1,42 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F130 + TextEditorState* TextEditorState ::Constructor_TextEditorState() + { + this->isDialogStateInitialized = 0; + this->helpDialogVariant = 0; + this->unknown_0x23960 = 0; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = 0; + this->customHelpTextLength = 0; + this->pendingTokenTypeToSkip = 0; + this->useWideHelpLayout = 0; + + MACRO_CALL_MEMBER(TextEditorState_Func::resetHelpStateFields, this)(); + + this->DAT_PointerToTemporaryTextMemory = MACRO_CALL(OS_Func::_malloc)(40000); + this->customTextMaxLength = -1; + + for (int counter = 0; counter < 500; ++counter) { + if (strlen(DAT_UserHelpDefinedData::instance.HelpSections[counter])) { + continue; + } + this->counter = counter; + break; + } + + for (int i = 0; i < 20; ++i) { + this->intArray1[i] = 0; + } + return this; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c51eb419db..6dc96a67e7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18749,7 +18749,7 @@ SHC_3BB0A8C1_0x0045F0D0 | 0.0% | Pending SHC_3BB0A8C1_0x0045F120 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045F130 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F130 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F240 | 0.0% | Pending From 04f4f006328f16b6bedbda0c0e13c40199922f35 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 6 Sep 2026 19:53:13 +0200 Subject: [PATCH 02/44] reimplement: SHC_3BB0A8C1_0x0045D080 100% --- .../Text/TextEditorState/setHelpWindowBounds.cpp | 16 ++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp diff --git a/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp b/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp new file mode 100644 index 0000000000..ba116919b2 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp @@ -0,0 +1,16 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D080 + void TextEditorState::setHelpWindowBounds(undefined4 x, undefined4 y, undefined4 height, undefined4 width) + { + this->dialogContentX = x; + this->dialogContentY = y; + this->dialogContentHeight = height; + this->dialogContentWidth = width; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6dc96a67e7..1442c5aeaf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18147,7 +18147,7 @@ SHC_3BB0A8C1_0x0045CD10 | 0.0% | Pending SHC_3BB0A8C1_0x0045D060 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D080 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D080 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D0B0 | 100.0% | Reimplemented From b066a7b23c47b8395fa07c5c9cc51e63f5a46a25 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 6 Sep 2026 19:56:35 +0200 Subject: [PATCH 03/44] reimplement: SHC_3BB0A8C1_0x0045D0C0 100% --- .../TextEditorState/resetHelpStateFields.cpp | 16 ++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/resetHelpStateFields.cpp diff --git a/src/OpenSHC/Text/TextEditorState/resetHelpStateFields.cpp b/src/OpenSHC/Text/TextEditorState/resetHelpStateFields.cpp new file mode 100644 index 0000000000..de0e1f34a9 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/resetHelpStateFields.cpp @@ -0,0 +1,16 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D0C0 + void TextEditorState::resetHelpStateFields() + { + for (int i = 0; i < 30; ++i) { + this->helpSectionHistoryStack[i] = -1; + } + this->currentHelpSectionID = -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1442c5aeaf..f0a3233192 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18151,7 +18151,7 @@ SHC_3BB0A8C1_0x0045D080 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D0B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D0C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D0C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D140 | 0.0% | Pending From 7b2bf257579817e75c85290a1bb8ec62f27f5b58 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 6 Sep 2026 20:00:48 +0200 Subject: [PATCH 04/44] reimplement: SHC_3BB0A8C1_0x0045D140 100% --- .../findHelpSectionIndexByName.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp b/src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp new file mode 100644 index 0000000000..018ef45a54 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp @@ -0,0 +1,22 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D140 + int TextEditorState::findHelpSectionIndexByName(char* param_1) + { + for (int counter = 0; counter < this->counter; ++counter) { + if (!MACRO_CALL(OS_Func::__stricmp)(DAT_UserHelpDefinedData::instance.HelpSections[counter], param_1)) { + return counter; + } + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f0a3233192..0133f73621 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18153,7 +18153,7 @@ SHC_3BB0A8C1_0x0045D0B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D0C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D140 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D140 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D1A0 | 0.0% | Pending From b4cd8aae7756a2cff34d01a69bc22dd54a28dbb2 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 6 Sep 2026 20:15:39 +0200 Subject: [PATCH 05/44] reimplement: SHC_3BB0A8C1_0x0045D1A0 100% --- .../Constructor_TextEditorState.cpp | 1 + .../findOrAddHelpSectionName.cpp | 32 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findOrAddHelpSectionName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp index 70d1b72d32..afb18c1b73 100644 --- a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp +++ b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp @@ -24,6 +24,7 @@ namespace Text { this->DAT_PointerToTemporaryTextMemory = MACRO_CALL(OS_Func::_malloc)(40000); this->customTextMaxLength = -1; + // FIXME:: Requires a finishing zero case, or it will not set the counter for (int counter = 0; counter < 500; ++counter) { if (strlen(DAT_UserHelpDefinedData::instance.HelpSections[counter])) { continue; diff --git a/src/OpenSHC/Text/TextEditorState/findOrAddHelpSectionName.cpp b/src/OpenSHC/Text/TextEditorState/findOrAddHelpSectionName.cpp new file mode 100644 index 0000000000..d1be3a1e57 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findOrAddHelpSectionName.cpp @@ -0,0 +1,32 @@ +// disable deprecation warnings for strcpy +#pragma warning(disable : 4996) + +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Text/TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D1A0 + int TextEditorState::findOrAddHelpSectionName(char* param_1) + { + int helpSectionId + = MACRO_CALL_MEMBER(OpenSHC::Text::TextEditorState_Func::findHelpSectionIndexByName, this)(param_1); + if (helpSectionId != -1) { + return helpSectionId; + } + // FIXME:: This should overflow the buffer if filled to much. The counter can reach 500, which is one over the + // buffer, ignoring that it will just overwrite this again and again. + helpSectionId = this->counter; + strcpy(DAT_UserHelpDefinedData::instance.HelpSections[helpSectionId], param_1); + if (this->counter < 500) { + ++this->counter; + } + return helpSectionId; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0133f73621..8a879afc10 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18155,7 +18155,7 @@ SHC_3BB0A8C1_0x0045D0C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D140 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D1A0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D1A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D200 | 0.0% | Pending From 29815ead4749c3afe7e1deb786ad2957b0e765e0 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Mon, 7 Sep 2026 22:12:55 +0200 Subject: [PATCH 06/44] reimplement: SHC_3BB0A8C1_0x0045D200 100% --- IMPLEMENTATION_CHEAT_SHEET.md | 2 + .../Text/TextEditorState/parseHLPPart.cpp | 78 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 12991e55dd..087740438f 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -386,6 +386,8 @@ you might have found an unrolled loop. Therefore, try to reproduce the logic in If GOTOs are present that clearly jump to the start of a loop, but the logic does not allow to do this without a GOTO, for example from a loop inside a loop, you might be able to move the continue or break condition to the outside. Methods could be placing a fitting condition related to the contained loop conditions after the loop or using a boolean flag that then functions as conditional. Both can sometimes be optimized away. +If an explicit loop condition is removed from the compiler, it is able to prove all paths through the loop. If such a case happens where the condition is actually eliminated from the re-implementation, the re-implementation might be missing a condition that is present in the logic somewhere, but removed from the loop condition itself. The optimization pass failed to detect the resulting predictable loop in this latter case and the condition remains. + A global used as a running counter alongside the loop index is usually incremented inside the loop, even when its final value is a constant. Ghidra shows the folded result: `DAT_CurrentUnitSlotID = 2500;` placed around the loop is really `DAT_CurrentUnitSlotID = 1;` before it and `DAT_CurrentUnitSlotID += 1;` as the first statement of the body. This was diff --git a/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp b/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp new file mode 100644 index 0000000000..f630aa3b06 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp @@ -0,0 +1,78 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/HLP_WCHAR_Buffer.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D200 + LPCWSTR TextEditorState::parseHLPPart(FILE* filePointer) + { + + int finishedParsing = FALSE; + int quoteActive = FALSE; + int reachedWEOF = FALSE; + wchar_t* bufferPtr = HLP_WCHAR_Buffer::instance; + while (!reachedWEOF) { + if (finishedParsing) { + return HLP_WCHAR_Buffer::instance; + } + + int readWChar = MACRO_CALL(OS_Func::_fgetwc)(filePointer); + switch (readWChar) { + case L'"': + quoteActive ^= TRUE; + continue; + + case L'\t': + case L' ': + case L',': + case L'=': + if (!quoteActive) { + int consumed = FALSE; + while (!reachedWEOF && !consumed) { + readWChar = MACRO_CALL(OS_Func::_fgetwc)(filePointer); + + if (readWChar == WEOF) { + reachedWEOF = TRUE; + continue; + } + + switch (readWChar) { + default: + MACRO_CALL(OS_Func::_fseek)(filePointer, -2, FILE_CURRENT); + case L'>': + consumed = true; + case L'\t': + case L' ': + case L',': + case L'=': + break; + } + } + } + case L'>': + if (!quoteActive) { + finishedParsing = true; + *bufferPtr = L'\0'; + continue; + } + break; + + case L'\n': + case L'\r': + continue; + + case WEOF: + reachedWEOF = true; + continue; + } + *bufferPtr++ = readWChar; + } + return NULL; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8a879afc10..438bf489b2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18157,7 +18157,7 @@ SHC_3BB0A8C1_0x0045D140 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D1A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D200 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D200 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D300 | 0.0% | Pending From 6483df4341c75e65a94c5c972d54c672e25c51cc Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Mon, 7 Sep 2026 22:30:24 +0200 Subject: [PATCH 07/44] reimplement: SHC_3BB0A8C1_0x0045D370 100% --- .../loadHelpSectionGraphics.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp diff --git a/src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp b/src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp new file mode 100644 index 0000000000..ea5ba6b532 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp @@ -0,0 +1,22 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" + +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D370 + void TextEditorState::loadHelpSectionGraphics() + { + DAT_TextureRenderCoreObject::instance.backwardsLoadedGfxIndex_0x16C850 = 99; + DAT_TextureRenderCoreObject::instance.loadedGfxArray[99].backwardsOffsetInBuffer = 0; + for (int i = 0; i < this->graphicFileCount; ++i) { + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::loadGfxAtBufferEnd, + DAT_TextureRenderCoreObject::ptr)(this->graphicFileNames[i]); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 438bf489b2..d16ced94ff 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18327,7 +18327,7 @@ SHC_3BB0A8C1_0x0045D364 | 0.0% | Pending SHC_3BB0A8C1_0x0045D365 | 0.0% | Pending -SHC_3BB0A8C1_0x0045D370 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D370 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D3C0 | 0.0% | Pending From 8bdf42abaee45cc521503f56979183a131ea061f Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Tue, 8 Sep 2026 22:06:19 +0200 Subject: [PATCH 08/44] reimplement: SHC_3BB0A8C1_0x0045D3C0 100% --- .../getWideCharOrWideCharPointer.cpp | 36 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp b/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp new file mode 100644 index 0000000000..7e28ededd5 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp @@ -0,0 +1,36 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_ARRAY_00df2b78.hpp" + +namespace OpenSHC { +namespace Text { + + // NOTE: Return is essentially a "union", however, it needs to be a value for the proper structure + // Also, it might be likely that this function is "known" by its only user "processHelpRichTextTokens" + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D3C0 + uint TextEditorState::getWideCharOrWideCharPointer(int* param_1) + { + int result = this->DAT_PointerToTemporaryTextMemory[*param_1]; + *param_1 += 1; + + if (result >= L' ') { + DAT_ARRAY_00df2b78::instance[0] = result; + + int length = 1; + while (this->DAT_PointerToTemporaryTextMemory[*param_1] >= L' ') { + DAT_ARRAY_00df2b78::instance[length] = this->DAT_PointerToTemporaryTextMemory[*param_1]; + *param_1 += 1; + ++length; + if (this->DAT_PointerToTemporaryTextMemory[*param_1 - 1] == L' ') { + break; + } + } + DAT_ARRAY_00df2b78::instance[length] = L'\0'; + result = (int)DAT_ARRAY_00df2b78::instance; + } + return (uint)result; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d16ced94ff..e649d37cc1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18329,7 +18329,7 @@ SHC_3BB0A8C1_0x0045D365 | 0.0% | Pending SHC_3BB0A8C1_0x0045D370 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D3C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D3C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D430 | 0.0% | Pending From a3ddfce53846ccab9b2dc6469cc74d78a35f91d9 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 00:06:47 +0200 Subject: [PATCH 09/44] reimplement: SHC_3BB0A8C1_0x0045D430 100% --- .../renderHelpImageHotspots.cpp | 73 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp diff --git a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp new file mode 100644 index 0000000000..d468a9d7c4 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp @@ -0,0 +1,73 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Input/MouseState.func.hpp" +#include "OpenSHC/UI/Rendering/PencilRenderCore.func.hpp" +#include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" + +#include "OpenSHC/Globals/COL_GREYISH_YELLOW.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" +#include "OpenSHC/Globals/DAT_PencilRenderCore.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D430 + void TextEditorState::renderHelpImageHotspots() + { + for (int i = 0; i < this->imageHotspotCount; ++i) { + int _gfxIndex = 99 - this->imageHotspotTable[i].imageRelated; + if ((this->useInGameHelpHandler || this->helpDialogVariant == 1) + && !MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::checkIfGfxTgxStartsWithTransparentPixels, + DAT_TextureRenderCoreObject::ptr)(_gfxIndex)) { + int x1 = this->imageHotspotTable[i].xPos + this->dialogContentX - 2; + int y1 = this->imageHotspotTable[i].yPos - this->helpContentScrollOffsetY + this->dialogContentY - 2; + int width = DAT_TextureRenderCoreObject::instance.loadedGfxArray[_gfxIndex].width + 3; + int height = DAT_TextureRenderCoreObject::instance.loadedGfxArray[_gfxIndex].height + 3; + if (y1 < this->dialogContentY) { + height += y1 - this->dialogContentY; + y1 = this->dialogContentY; + } + // Does the naming "dialogContentWidth" fit? Is it related to width? + if (height + y1 > this->dialogContentY + this->dialogContentWidth) { + height = this->dialogContentWidth * 2 - y1; + } + int const y2 = y1 + height; + if (y2 >= this->dialogContentY && y1 < this->dialogContentY + this->dialogContentWidth) { + int const x2 = x1 + width; + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1, y1, x2, y1, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1, y1 + 1, x2, y1 + 1, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1, y2, x2, y2, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1, y2 + -1, x2, y2 + -1, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1, y1, x1, y2, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x1 + 1, y1, x1 + 1, y2, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x2, y1, x2, y2, COL_GREYISH_YELLOW::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + x2 + -1, y1, x2 + -1, y2, COL_GREYISH_YELLOW::instance.shortValue); + } + } + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::drawGfxOnFlaggedSurface, + DAT_TextureRenderCoreObject::ptr)(_gfxIndex, this->imageHotspotTable[i].xPos + this->dialogContentX, + this->imageHotspotTable[i].yPos - this->helpContentScrollOffsetY + this->dialogContentY); + + int const boxHeight = DAT_TextureRenderCoreObject::instance.loadedGfxArray[_gfxIndex].height; + int const boxWidth = DAT_TextureRenderCoreObject::instance.loadedGfxArray[_gfxIndex].width; + if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + this->imageHotspotTable[i].xPos - this->helpContentScrollX + this->dialogContentX, + this->imageHotspotTable[i].yPos - this->helpContentScrollY + this->dialogContentY + - this->helpContentScrollOffsetY, + boxWidth, boxHeight)) { + this->unknown_0x23968 = this->imageHotspotTable[i].unknown3; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e649d37cc1..abdb506920 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18331,7 +18331,7 @@ SHC_3BB0A8C1_0x0045D370 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D3C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D430 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D430 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D460 | 0.0% | Pending From 90ce68b9f42e83a7d055700853d017dcf5e48f2b Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 00:19:29 +0200 Subject: [PATCH 10/44] reimplement: SHC_3BB0A8C1_0x0045D690 100% --- .../bltTextToScreenIfNeedBe.cpp | 27 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp diff --git a/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp b/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp new file mode 100644 index 0000000000..d6bb78b88b --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp @@ -0,0 +1,27 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/Rendering/WindowAndDirectDraw.func.hpp" + +#include "OpenSHC/Globals/DAT_TextEditorState.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D690 + void TextEditorState::bltTextToScreenIfNeedBe() + { + if (!DAT_TextEditorState::instance.unknown_0x23960) { + return; + } + if (this->savedMenuViewType == UI::Enums::MVT_MAP_EDITOR_LANDSCAPING + || this->savedMenuViewType == UI::Enums::MVT_BUILD_MENU + || this->savedMenuViewType == UI::Enums::MVT_BUILDING_AND_STATUS_MENU) { + MACRO_CALL_MEMBER(UI::Rendering::WindowAndDirectDraw_Func::bltMapGameSurfaceToScreenMenuSurfaceComplete, + DAT_WindowAndDirectDraw::ptr)(); + } + DAT_TextEditorState::instance.unknown_0x23960 = FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index abdb506920..1b13f6cea3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18335,7 +18335,7 @@ SHC_3BB0A8C1_0x0045D430 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D460 | 0.0% | Pending -SHC_3BB0A8C1_0x0045D690 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D690 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D6C0 | 0.0% | Pending From 8d0f978e7f217afbb32e98712f3d9e85890509aa Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 21:22:26 +0200 Subject: [PATCH 11/44] reimplement: SHC_3BB0A8C1_0x0045D6C0 100% --- .../TextEditorState/drawBorderStyle0x20.cpp | 37 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp diff --git a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp new file mode 100644 index 0000000000..c36e3e66ae --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp @@ -0,0 +1,37 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D6C0 + void TextEditorState::drawBorderStyle0x20(int dialogX, int dialogY, int dialogWidth, int dialogHeight) + { + this->dialogX = dialogX; + this->dialogY = dialogY; + this->dialogWidth = dialogWidth; + this->dialogHeight = dialogHeight; + + // NOTE: dialogWidth is used to compute the content height and vice versa, no idea if something was switched; + // also, the required order feels strange, maybe they used a RECT struct or macro + // FIXME: ContentHeight and ContentWidth or the dialogWidth and dialogHeight are swapped + int const contentX = this->dialogX + DAT_00df2964::instance; + int const contentY = this->dialogY + DAT_00df296c::instance; + int const contentWidth = this->dialogHeight - INT_00df2970::instance; + int const contentHeight = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = contentX; + this->dialogContentY = contentY; + this->dialogContentHeight = contentHeight; + this->dialogContentWidth = contentWidth; + + this->helpContentScrollX = DAT_ViewportRenderState::instance.viewportState.currentCameraOffsetX; + this->helpContentScrollY = DAT_ViewportRenderState::instance.viewportState.currentCameraOffsetY; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1b13f6cea3..3648fcc22c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18337,7 +18337,7 @@ SHC_3BB0A8C1_0x0045D460 | 0.0% | Pending SHC_3BB0A8C1_0x0045D690 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D6C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D6C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D740 | 0.0% | Pending From fa58174f665e64663239ffbb5029eb479c47b439 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 22:00:49 +0200 Subject: [PATCH 12/44] reimplement: SHC_3BB0A8C1_0x0045D200 update return type --- src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp b/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp index f630aa3b06..cc97503d33 100644 --- a/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp +++ b/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp @@ -8,7 +8,7 @@ namespace OpenSHC { namespace Text { // FUNCTION: STRONGHOLDCRUSADER 0x0045D200 - LPCWSTR TextEditorState::parseHLPPart(FILE* filePointer) + LPWSTR TextEditorState::parseHLPPart(FILE* filePointer) { int finishedParsing = FALSE; From 2a57a09e5cb302173d15bda891ebd091ca7bae6c Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 22:53:30 +0200 Subject: [PATCH 13/44] reimplement: SHC_3BB0A8C1_0x0045D740 100% --- .../drawHelpWindowBackground.cpp | 52 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp diff --git a/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp b/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp new file mode 100644 index 0000000000..ac5555d629 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp @@ -0,0 +1,52 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/Rendering/PencilRenderCore.func.hpp" + +#include "OpenSHC/Globals/COL_BLACK.hpp" +#include "OpenSHC/Globals/COL_DARK_CYAN_GREY.hpp" +#include "OpenSHC/Globals/COL_VERY_DARK_GREY.hpp" +#include "OpenSHC/Globals/DAT_PencilRenderCore.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D740 + void TextEditorState::drawHelpWindowBackground() + { + if (this->helpDialogVariant != 1) { + DAT_TextureRenderCoreObject::instance.drawBufferChoiceValue = Rendering::Enums::RT_SCREEN_MENU; + } else { + DAT_TextManagerObject::instance.textSurfaceTarget = Rendering::Enums::RT_MAP_GAME; + DAT_PencilRenderCore::instance.surfaceTarget = Rendering::Enums::RT_MAP_GAME; + } + if (this->isCustomTextMode) { + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawBoxWithRoundedEdges, DAT_PencilRenderCore::ptr)( + this->dialogX, this->dialogY, this->dialogWidth + this->dialogX, this->dialogHeight + this->dialogY, + UI::Enums::RBERL_SLIGHT); + } else if (!this->useAlternateHelpTab) { + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( + this->dialogX, this->dialogY, this->dialogWidth + this->dialogX, this->dialogHeight + this->dialogY, + COL_BLACK::instance.shortValue); + } else if (this->helpDialogVariant != 2) { + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( + this->dialogX, this->dialogY, this->dialogWidth + this->dialogX, this->dialogHeight + this->dialogY, + COL_VERY_DARK_GREY::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( + this->dialogContentX, this->dialogContentY, this->dialogContentHeight + this->dialogContentX, + this->dialogContentWidth + this->dialogContentY, COL_BLACK::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( + this->dialogX, this->dialogY + this->dialogHeight, this->dialogWidth + this->dialogX, + this->dialogY + this->dialogHeight + 60, COL_DARK_CYAN_GREY::instance.shortValue); + } + if (this->helpDialogVariant != 1) { + DAT_TextureRenderCoreObject::instance.drawBufferChoiceValue = Rendering::Enums::RT_MAP_GAME; + } else { + DAT_TextManagerObject::instance.textSurfaceTarget = Rendering::Enums::RT_SCREEN_MENU; + DAT_PencilRenderCore::instance.surfaceTarget = Rendering::Enums::RT_SCREEN_MENU; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3648fcc22c..fa62413d4f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18339,7 +18339,7 @@ SHC_3BB0A8C1_0x0045D690 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D6C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D740 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D740 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D890 | 0.0% | Pending From 0c55173e6077f83d32d272875254d5e5b667930a Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Wed, 9 Sep 2026 23:06:18 +0200 Subject: [PATCH 14/44] reimplement: SHC_3BB0A8C1_0x0045D890 100% --- .../findHelpGraphicIndexByName.cpp | 20 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findHelpGraphicIndexByName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/findHelpGraphicIndexByName.cpp b/src/OpenSHC/Text/TextEditorState/findHelpGraphicIndexByName.cpp new file mode 100644 index 0000000000..76afd0b00a --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findHelpGraphicIndexByName.cpp @@ -0,0 +1,20 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D890 + int TextEditorState::findHelpGraphicIndexByName(char* param_1) + { + for (int i = 0; i < this->graphicFileCount; ++i) { + if (!MACRO_CALL(OS_Func::__stricmp)(this->graphicFileNames[i], param_1)) { + return i; + } + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fa62413d4f..d51251c9a2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18341,7 +18341,7 @@ SHC_3BB0A8C1_0x0045D6C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D740 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D890 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D8F0 | 0.0% | Pending From 130ea72a26c26703954b3679176ae949b2c1fa2f Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:13:21 +0200 Subject: [PATCH 15/44] reimplement: SHC_3BB0A8C1_0x0045D8F0 100% --- .../findOrAddHelpGraphicName.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findOrAddHelpGraphicName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/findOrAddHelpGraphicName.cpp b/src/OpenSHC/Text/TextEditorState/findOrAddHelpGraphicName.cpp new file mode 100644 index 0000000000..4e668a43b1 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findOrAddHelpGraphicName.cpp @@ -0,0 +1,25 @@ +// disable deprecation warnings for strcpy +#pragma warning(disable : 4996) + +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D8F0 + int TextEditorState::findOrAddHelpGraphicName(char* param_1) + { + int graphicIndex = MACRO_CALL_MEMBER(TextEditorState_Func::findHelpGraphicIndexByName, this)(param_1); + if (graphicIndex != -1) { + return graphicIndex; + } + graphicIndex = this->graphicFileCount; + strcpy(this->graphicFileNames[graphicIndex], param_1); + if (this->graphicFileCount < 20) { + ++this->graphicFileCount; + } + return graphicIndex; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d51251c9a2..bd053e5b22 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18343,7 +18343,7 @@ SHC_3BB0A8C1_0x0045D740 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D890 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D8F0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D8F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D950 | 0.0% | Pending From c8f53bb72ff2db2f31c7c5e23ecbe8de3f535126 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:30:24 +0200 Subject: [PATCH 16/44] reimplement: SHC_3BB0A8C1_0x0045D950 100% --- .../TextEditorState/getNextHelpSectionID.cpp | 26 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getNextHelpSectionID.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getNextHelpSectionID.cpp b/src/OpenSHC/Text/TextEditorState/getNextHelpSectionID.cpp new file mode 100644 index 0000000000..dd1e12b331 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getNextHelpSectionID.cpp @@ -0,0 +1,26 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D950 + int TextEditorState::getNextHelpSectionID(int param_1) + { + for (int index = 0; DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 != -1; ++index) { + if (DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 != param_1) { + continue; + } + + ++index; + if (DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 == -1) { + index = 0; + } + return DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4; + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bd053e5b22..b980df5369 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18345,7 +18345,7 @@ SHC_3BB0A8C1_0x0045D890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D8F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D950 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D950 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D990 | 0.0% | Pending From c37f34a1505783f9ea509dc17b45c952ea22ea62 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:55:11 +0200 Subject: [PATCH 17/44] reimplement: SHC_3BB0A8C1_0x0045D990 100% --- .../TextEditorState/getPrevHelpSectionID.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getPrevHelpSectionID.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getPrevHelpSectionID.cpp b/src/OpenSHC/Text/TextEditorState/getPrevHelpSectionID.cpp new file mode 100644 index 0000000000..4e5d3ba84d --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getPrevHelpSectionID.cpp @@ -0,0 +1,28 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D990 + int TextEditorState::getPrevHelpSectionID(int param_1) + { + for (int index = 0; DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 != -1; ++index) { + if (DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 == param_1) { + --index; + if (index < 0) { + index = 0; + while (DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 != -1) { + ++index; + } + --index; + } + return DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4; + } + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b980df5369..fe7ed1a294 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18347,7 +18347,7 @@ SHC_3BB0A8C1_0x0045D8F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D950 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D990 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D990 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D9E0 | 0.0% | Pending From a4c403ad67f2dd91c03f0991d262e90622fc4aae Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 21:58:52 +0200 Subject: [PATCH 18/44] reimplement: SHC_3BB0A8C1_0x0045D9E0 100% --- .../TextEditorState/getHelpSectionText.cpp | 20 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getHelpSectionText.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getHelpSectionText.cpp b/src/OpenSHC/Text/TextEditorState/getHelpSectionText.cpp new file mode 100644 index 0000000000..a0c88560bb --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getHelpSectionText.cpp @@ -0,0 +1,20 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045D9E0 + char* TextEditorState::getHelpSectionText(int param_1) + { + for (int index = 0; DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 != -1; ++index) { + if (DAT_UserHelpDefinedData::instance.field5_0x7a124[index].unknown_0x4 == param_1) { + return DAT_UserHelpDefinedData::instance.field5_0x7a124[index].text_0x0; + } + } + return NULL; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fe7ed1a294..a8f6283e92 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18349,7 +18349,7 @@ SHC_3BB0A8C1_0x0045D950 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D990 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045D9E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D9E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DA20 | 0.0% | Pending From 55f21bc6dd56641f21f79d2100dfb54f35e65851 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 22:03:26 +0200 Subject: [PATCH 19/44] reimplement: SHC_3BB0A8C1_0x0045DA20 100% --- .../getNextHelpColorEntryIndex.cpp | 19 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getNextHelpColorEntryIndex.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getNextHelpColorEntryIndex.cpp b/src/OpenSHC/Text/TextEditorState/getNextHelpColorEntryIndex.cpp new file mode 100644 index 0000000000..98ad9021a8 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getNextHelpColorEntryIndex.cpp @@ -0,0 +1,19 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045DA20 + int TextEditorState::getNextHelpColorEntryIndex(int param_1) + { + int newIndex = param_1 + 1; + if (DAT_UserHelpDefinedData::instance.field6_0x7a16c[newIndex].name_0x0 == NULL) { + newIndex = 0; + } + return newIndex; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a8f6283e92..cd96647ce5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18351,7 +18351,7 @@ SHC_3BB0A8C1_0x0045D990 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D9E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045DA20 | 0.0% | Pending +SHC_3BB0A8C1_0x0045DA20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DA40 | 0.0% | Pending From 56d82f19d28199ec7d326cf578cb274eaaabe182 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 10 Sep 2026 22:09:16 +0200 Subject: [PATCH 20/44] reimplement: SHC_3BB0A8C1_0x0045DA40 100% --- .../getPrevHelpColorEntryIndex.cpp | 23 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getPrevHelpColorEntryIndex.cpp diff --git a/src/OpenSHC/Text/TextEditorState/getPrevHelpColorEntryIndex.cpp b/src/OpenSHC/Text/TextEditorState/getPrevHelpColorEntryIndex.cpp new file mode 100644 index 0000000000..d3f15557e1 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/getPrevHelpColorEntryIndex.cpp @@ -0,0 +1,23 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045DA40 + int TextEditorState::getPrevHelpColorEntryIndex(int param_1) + { + --param_1; + if (param_1 < 0) { + param_1 = 0; + while (DAT_UserHelpDefinedData::instance.field6_0x7a16c[param_1].name_0x0 != NULL) { + ++param_1; + } + --param_1; + } + return param_1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index cd96647ce5..e0d0506039 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18353,7 +18353,7 @@ SHC_3BB0A8C1_0x0045D9E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DA20 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045DA40 | 0.0% | Pending +SHC_3BB0A8C1_0x0045DA40 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DA60 | 0.0% | Pending From 8c1577acd31c4ec9a9ee493b570e21d97381231c Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Fri, 11 Sep 2026 22:44:36 +0200 Subject: [PATCH 21/44] reimplement: SHC_3BB0A8C1_0x0045DA80 100% --- .../TextEditorState/findSoundIndexByName.cpp | 20 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp b/src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp new file mode 100644 index 0000000000..f105e1de41 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp @@ -0,0 +1,20 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045DA80 + int TextEditorState::findSoundIndexByName(char* param_1) + { + for (int i = 0; i < this->soundFileCount; i = i + 1) { + if (!MACRO_CALL(OpenSHC::OS_Func::__stricmp)(this->soundFileNames[i], param_1)) { + return i; + } + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e0d0506039..888b2b8850 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18357,7 +18357,7 @@ SHC_3BB0A8C1_0x0045DA40 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DA60 | 0.0% | Pending -SHC_3BB0A8C1_0x0045DA80 | 0.0% | Pending +SHC_3BB0A8C1_0x0045DA80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DAE0 | 0.0% | Pending From f5b5d9656148b1d2bae2868a85a8479464439ac6 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Fri, 11 Sep 2026 22:53:05 +0200 Subject: [PATCH 22/44] reimplement: SHC_3BB0A8C1_0x0045DAE0 100% --- .../TextEditorState/findOrAddSoundName.cpp | 29 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findOrAddSoundName.cpp diff --git a/src/OpenSHC/Text/TextEditorState/findOrAddSoundName.cpp b/src/OpenSHC/Text/TextEditorState/findOrAddSoundName.cpp new file mode 100644 index 0000000000..154d8464b8 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/findOrAddSoundName.cpp @@ -0,0 +1,29 @@ +// disable deprecation warnings for strcpy +#pragma warning(disable : 4996) + +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Text/TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045DAE0 + int TextEditorState::findOrAddSoundName(char* param_1) + { + int index = MACRO_CALL_MEMBER(OpenSHC::Text::TextEditorState_Func::findSoundIndexByName, this)(param_1); + if (index != -1) { + return index; + } + + index = this->soundFileCount; + strcpy(this->soundFileNames[index], param_1); + this->soundFilePlayedFlags[index] = 0; + if (this->soundFileCount < 5) { + ++this->soundFileCount; + } + return index; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 888b2b8850..47be1a72fe 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18359,7 +18359,7 @@ SHC_3BB0A8C1_0x0045DA60 | 0.0% | Pending SHC_3BB0A8C1_0x0045DA80 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045DAE0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045DAE0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DB40 | 0.0% | Pending From 7434c6e2e982ab158fd6c3a31c2917a30756a8ef Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sat, 12 Sep 2026 20:08:33 +0200 Subject: [PATCH 23/44] reimplement: SHC_3BB0A8C1_0x0045DB40 100% --- src/OpenSHC/OS.func.hpp | 4 + src/OpenSHC/OS.hpp | 2 + src/OpenSHC/OS/OS.cpp | 11 ++ .../saveHelpFileToResource.cpp | 118 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp diff --git a/src/OpenSHC/OS.func.hpp b/src/OpenSHC/OS.func.hpp index 4523a08354..c11a6c39ee 100644 --- a/src/OpenSHC/OS.func.hpp +++ b/src/OpenSHC/OS.func.hpp @@ -179,5 +179,9 @@ namespace OS_Func { void(__cdecl*)(int _Code), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00583D55, &OpenSHC::OS::_exit) _exit; + MACRO_FUNCTION_RESOLVER(int(__cdecl*)(FILE*, wchar_t const*, ...), REIMPLEMENTED_CRT, + Address::SHC_3BB0A8C1_0x005807A8, &OpenSHC::OS::_fwprintf) + _fwprintf; + } // namespace OS_Func } // namespace OpenSHC diff --git a/src/OpenSHC/OS.hpp b/src/OpenSHC/OS.hpp index b0cad4b807..710bea1f5b 100644 --- a/src/OpenSHC/OS.hpp +++ b/src/OpenSHC/OS.hpp @@ -103,5 +103,7 @@ namespace OS { void __cdecl _exit(int _Code); + int _fwprintf(FILE* stream, wchar_t const* format, ...); + } // namespace OS } // namespace OpenSHC diff --git a/src/OpenSHC/OS/OS.cpp b/src/OpenSHC/OS/OS.cpp index 0579726352..bc455be207 100644 --- a/src/OpenSHC/OS/OS.cpp +++ b/src/OpenSHC/OS/OS.cpp @@ -146,5 +146,16 @@ namespace OS { // STUB: STRONGHOLDCRUSADER 0x00583D55 void _exit(int _Code) { exit(_Code); } + // STUB: STRONGHOLDCRUSADER 0x005807A8 + int _fwprintf(FILE* stream, wchar_t const* format, ...) + { + // needed for proxy + va_list args; + va_start(args, format); + int result = vfwprintf(stream, format, args); + va_end(args); + return result; + } + } } diff --git a/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp b/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp new file mode 100644 index 0000000000..1ae12edc84 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp @@ -0,0 +1,118 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/IO/ResourceManager.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + // TODO: Replace L strings with references from a file + + // FUNCTION: STRONGHOLDCRUSADER 0x0045DB40 + void TextEditorState::saveHelpFileToResource() + { + MACRO_CALL_MEMBER(IO::ResourceManager_Func::resolveResourceFileName, DAT_ResourceManager::ptr)( + IO::FRT_HELP, DAT_UserHelpDefinedData::instance.HelpSections[this->currentHelpSectionID]); + char const* const _Filename = MACRO_CALL_MEMBER( + IO::ResourceManager_Func::getFileNameOfCurrentActiveResource, DAT_ResourceManager::ptr)(); + FILE* _File = MACRO_CALL(OS_Func::_fopen)(_Filename, s_wb_005a5510); + if (!_File) { + return; + } + wchar_t const utf16bom = L'\uFEFF'; + MACRO_CALL(OS_Func::_fwrite)((void*)&utf16bom, sizeof(wchar_t), 1, _File); + + MACRO_CALL(OS_Func::_fwprintf)(_File, L"
\n"); + for (int i = 0; i < this->graphicFileCount; ++i) { + MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n", this->graphicFileNames[i]); + } + MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\HEADER>\n"); + MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n"); + + for (int i = 0; this->DAT_PointerToTemporaryTextMemory[i];) { + HelpTextToken const switchValue = (HelpTextToken)this->DAT_PointerToTemporaryTextMemory[i]; + i += 1; + switch (switchValue) { + case HTT_PIC: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"DAT_PointerToTemporaryTextMemory[i]); + i += 1; + switch ((HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[i]) { + case HTT_PIC_LEFT: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"LEFT>"); + i += 2; + break; + case HTT_PIC_RIGHT: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"RIGHT>"); + i += 2; + break; + case HTT_PIC_CENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"CENTRE>"); + i += 2; + break; + case HTT_PIC_HERE: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"HERE>"); + default: + i += 2; + break; + } + break; + case HTT_FONT: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + i += 2; + break; + case HTT_COLOUR: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + i += 2; + break; + case HTT_LINKCOLOUR: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + i += 2; + break; + case HTT_LINK: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", + DAT_UserHelpDefinedData::instance.HelpSections[this->DAT_PointerToTemporaryTextMemory[i]]); + i += 2; + break; + case HTT_INCLUDE: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", + DAT_UserHelpDefinedData::instance.HelpSections[this->DAT_PointerToTemporaryTextMemory[i]]); + i += 2; + break; + case HTT_ENDLINK: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\LINK>"); + break; + case HTT_NEWPARAGRAPH: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n\n"); + break; + case HTT_CENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, L""); + break; + case HTT_ENDCENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\CENTRE>"); + break; + case HTT_SOUND: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + i += 2; + break; + case HTT_STRING: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + i += 2; + break; + default: + MACRO_CALL(OS_Func::_fwprintf)(_File, L"%c", (wchar_t)switchValue); + break; + } + } + + MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n<\\BODY>\n"); + MACRO_CALL(OS_Func::_fclose)(_File); + } + +#undef MACRO_TEXT_ACCESS + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 47be1a72fe..e58142a892 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18361,7 +18361,7 @@ SHC_3BB0A8C1_0x0045DA80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DAE0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045DB40 | 0.0% | Pending +SHC_3BB0A8C1_0x0045DB40 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045DDF4 | 0.0% | Pending From beb3ad76bc7a1d6d08cf97bd5316a1b590d42e31 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sat, 12 Sep 2026 21:38:53 +0200 Subject: [PATCH 24/44] reimplement: SHC_3BB0A8C1_0x0045F080 and SHC_3BB0A8C1_0x0045F0D0 100% --- .../Text/TextEditorState/helpToken.cpp | 39 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/helpToken.cpp diff --git a/src/OpenSHC/Text/TextEditorState/helpToken.cpp b/src/OpenSHC/Text/TextEditorState/helpToken.cpp new file mode 100644 index 0000000000..6931a374e6 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/helpToken.cpp @@ -0,0 +1,39 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F080 + int TextEditorState::helpToken_getHelpTokenAdvanceLength(HelpTextToken token) + { + switch (token) { + case HTT_PIC: + return 4; + + case HTT_FONT: + case HTT_COLOUR: + case HTT_LINK: + case HTT_LINKCOLOUR: + case HTT_SOUND: + case HTT_STRING: + case HTT_INCLUDE: + return 3; + + default: + return 1; + } + } + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F0D0 + void TextEditorState::helpToken_insertSpaceForHelpTextToken(HelpTextToken token) + { + int tokenLength = MACRO_CALL_MEMBER(TextEditorState_Func::helpToken_getHelpTokenAdvanceLength, this)(token); + for (int textIndex = this->customHelpTextLength; textIndex >= this->activeHelpHotspotIndex; --textIndex) { + this->DAT_PointerToTemporaryTextMemory[textIndex + tokenLength] + = this->DAT_PointerToTemporaryTextMemory[textIndex]; + } + this->customHelpTextLength += tokenLength; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e58142a892..a59ea814d0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18709,7 +18709,7 @@ SHC_3BB0A8C1_0x0045EF84 | 0.0% | Pending SHC_3BB0A8C1_0x0045EF90 | 0.0% | Pending -SHC_3BB0A8C1_0x0045F080 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F080 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F0B4 | 0.0% | Pending @@ -18745,7 +18745,7 @@ SHC_3BB0A8C1_0x0045F0CC | 0.0% | Pending SHC_3BB0A8C1_0x0045F0CD | 0.0% | Pending -SHC_3BB0A8C1_0x0045F0D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F0D0 | 100.0% | Reimplemented, requires SHC_3BB0A8C1_0x0045F130 active SHC_3BB0A8C1_0x0045F120 | 100.0% | Reimplemented From 67c28dad98e8cef2f3e3d7e224e1b598ace18cd5 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sat, 12 Sep 2026 22:08:50 +0200 Subject: [PATCH 25/44] reimplement: SHC_3BB0A8C1_0x0045F240 100% --- .../closeHelpDialogAndReturnToMenu.cpp | 78 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/closeHelpDialogAndReturnToMenu.cpp diff --git a/src/OpenSHC/Text/TextEditorState/closeHelpDialogAndReturnToMenu.cpp b/src/OpenSHC/Text/TextEditorState/closeHelpDialogAndReturnToMenu.cpp new file mode 100644 index 0000000000..04a89a4211 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/closeHelpDialogAndReturnToMenu.cpp @@ -0,0 +1,78 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/UI/MenuModalComposition.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_MenuView_TriggerPrepare.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F240 + void TextEditorState::closeHelpDialogAndReturnToMenu() + { + if (!this->isDialogStateInitialized) { + return; + } + MACRO_CALL_MEMBER(TextEditorState_Func::resetHelpStateFields, this)(); + this->isDialogStateInitialized = 0; + + if (this->isCustomTextMode) { + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_NONE, FALSE); + for (int i = 0; i < 20; ++i) { + this->intArray1[i] = 0; + } + if (this->customHelpTextPointer) { + if (!this->isCustomHelpTextWide) { + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(this->customHelpTextPointer, + this->DAT_PointerToTemporaryTextMemory, this->customHelpTextBufferSize); + } else { + MACRO_CALL(OS_Func::_wcsncpy)((wchar_t*)this->customHelpTextPointer, + this->DAT_PointerToTemporaryTextMemory, this->customHelpTextBufferSize); + } + } + DAT_MenuView_TriggerPrepare::instance = TRUE; + + } else if (this->helpDialogVariant == 0) { + + if (this->savedMenuViewType == UI::Enums::MVT_BUILD_MENU) { + DAT_GameCore::instance.buildmenuMenuTabToSwitchTo.tabType = this->savedActiveMenuTab; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + (UI::Enums::MenuViewType)this->savedMenuViewType, 0); + + } else if (this->savedMenuViewType == UI::Enums::MVT_MAP_EDITOR_LANDSCAPING) { + DAT_GameCore::instance.landscapingmenuMenuTabToSwitchTo = this->savedActiveMenuTab; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + (UI::Enums::MenuViewType)this->savedMenuViewType, 0); + + } else if (this->savedMenuViewType == UI::Enums::MVT_BUILDING_AND_STATUS_MENU) { + DAT_GameCore::instance.buildingandstatusmenuMenuTabToSwitchTo = this->savedActiveMenuTab; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + (UI::Enums::MenuViewType)this->savedMenuViewType, 0); + + } else { + DAT_GameCore::instance.menuTabToSwitchTo.tabType = this->savedActiveMenuTab; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + (UI::Enums::MenuViewType)this->savedMenuViewType, 0); + } + + } else { + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_NONE, FALSE); + for (int i = 0; i < 20; ++i) { + this->intArray1[i] = 0; + } + } + + this->helpDialogVariant = 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a59ea814d0..c0c18c8836 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18751,7 +18751,7 @@ SHC_3BB0A8C1_0x0045F120 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F130 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045F240 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F240 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F470 | 0.0% | Pending From 00fdfc159e93c3616faa58bb408dd3e3af559b62 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 13 Sep 2026 00:11:00 +0200 Subject: [PATCH 26/44] reimplement: SHC_3BB0A8C1_0x0045F470 100% --- .../TextEditorState/readCrusaderHelpHlp.cpp | 66 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp diff --git a/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp b/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp new file mode 100644 index 0000000000..1f6bf9c84a --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp @@ -0,0 +1,66 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/IO/ResourceManager.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" + +namespace OpenSHC { +namespace Text { + + // TODO: Replace L-strings with str-ptr + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F470 + FILE* TextEditorState::readCrusaderHelpHlp(LPCSTR searchedPart) + { + this->helpSectionParseSucceeded = FALSE; + + WCHAR searchedPartWide[200]; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharacter, DAT_WideCharMultiByteState::ptr)( + searchedPartWide, searchedPart); + MACRO_CALL_MEMBER(IO::ResourceManager_Func::resolveResourceFileName, DAT_ResourceManager::ptr)( + IO::FRT_HELP, s_crusader_help_hlp_005a5620); + + char const* const _Filename = MACRO_CALL_MEMBER( + IO::ResourceManager_Func::getFileNameOfCurrentActiveResource, DAT_ResourceManager::ptr)(); + FILE* _File = MACRO_CALL(OS_Func::_fopen)(_Filename, s_rb_005a4e18); + if (_File) { + MACRO_CALL(OS_Func::_fseek)(_File, 2, FILE_BEGIN); // Skip BOM? + + int wideChar; + while (true) { + wideChar = MACRO_CALL(OS_Func::_fgetwc)(_File); + if (wideChar != L'<') { + if (wideChar == WEOF) { + return _File; + } + continue; + } + wchar_t* hlpPart = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(_File); + if (!hlpPart || MACRO_CALL(OS_Func::__wcsicmp)(L"section", hlpPart)) { + continue; + } + wchar_t* sectionHlpPart = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(_File); + if (!sectionHlpPart || MACRO_CALL(OS_Func::__wcsicmp)(searchedPartWide, sectionHlpPart)) { + continue; + } + break; + }; + + do { + wideChar = MACRO_CALL(OS_Func::_fgetwc)(_File); + if (wideChar == L'>') { + this->helpSectionParseSucceeded = TRUE; + break; + } + } while (wideChar != WEOF); + } + + return _File; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c0c18c8836..bc9e75068a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18753,7 +18753,7 @@ SHC_3BB0A8C1_0x0045F130 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F240 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045F470 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F470 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F580 | 0.0% | Pending From 6308b41708e7efbd70933331f63f91205b88b9b0 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 13 Sep 2026 00:20:31 +0200 Subject: [PATCH 27/44] reimplement: SHC_3BB0A8C1_0x0045F580 100% --- .../TextEditorState/loadAndParseHelpFile.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp diff --git a/src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp b/src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp new file mode 100644 index 0000000000..7a0e6bf844 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp @@ -0,0 +1,22 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F580 + BOOLEnum TextEditorState::loadAndParseHelpFile(char const* searchedPart) + { + FILE* _File = MACRO_CALL_MEMBER(TextEditorState_Func::readCrusaderHelpHlp, this)(searchedPart); + if (_File) { + MACRO_CALL(OS_Func::_fclose)(_File); + if (this->helpSectionParseSucceeded) { + return TRUE; + } + } + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bc9e75068a..78fedf7d06 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18755,7 +18755,7 @@ SHC_3BB0A8C1_0x0045F240 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F470 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045F580 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F580 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F5B0 | 0.0% | Pending From d7a520cd01f5dc206e59517ae767478bcf8081fd Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 13 Sep 2026 20:57:24 +0200 Subject: [PATCH 28/44] reimplement: SHC_3BB0A8C1_0x0045F5B0 99% --- IMPLEMENTATION_CHEAT_SHEET.md | 1 + src/OpenSHC/OS.func.hpp | 4 + src/OpenSHC/OS.hpp | 2 + src/OpenSHC/OS/OS.cpp | 3 + src/OpenSHC/Text/TextEditorState/parseHlp.cpp | 352 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 6 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/parseHlp.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 087740438f..6a19c9856d 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -319,6 +319,7 @@ SEC_RNG::ptr->currentNumber1 % 4 } ``` Consider this, should a switch structure arise with strange fallthrough and loops, like SHC_3BB0A8C1_0x004870B0. +- Non-consecutive case labels will likely result in a mixture of if-else and switch cases, sometimes even only if-elses. These are hard to spot. One sign, outside of weird decompiler artifacts, is that logic might be put inside a lot of conditions that feature only a single variable. Another can be a lot of GOTOs. - Write a comparison with its operands in the order the assembly shows. `if (a > b)` gives `cmp eax, ecx` where `if (b < a)` gives `cmp ecx, eax`; flipping seven `iVar6 < lag[n].average1` to `lag[n].average1 > iVar6` took diff --git a/src/OpenSHC/OS.func.hpp b/src/OpenSHC/OS.func.hpp index c11a6c39ee..1be1b6d1ee 100644 --- a/src/OpenSHC/OS.func.hpp +++ b/src/OpenSHC/OS.func.hpp @@ -183,5 +183,9 @@ namespace OS_Func { Address::SHC_3BB0A8C1_0x005807A8, &OpenSHC::OS::_fwprintf) _fwprintf; + MACRO_FUNCTION_RESOLVER( + long(__cdecl*)(wchar_t const*), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00580C0B, &OpenSHC::OS::__wtol) + __wtol; + } // namespace OS_Func } // namespace OpenSHC diff --git a/src/OpenSHC/OS.hpp b/src/OpenSHC/OS.hpp index 710bea1f5b..de952d1600 100644 --- a/src/OpenSHC/OS.hpp +++ b/src/OpenSHC/OS.hpp @@ -105,5 +105,7 @@ namespace OS { int _fwprintf(FILE* stream, wchar_t const* format, ...); + long __wtol(wchar_t const* str); + } // namespace OS } // namespace OpenSHC diff --git a/src/OpenSHC/OS/OS.cpp b/src/OpenSHC/OS/OS.cpp index bc455be207..e300ed41a5 100644 --- a/src/OpenSHC/OS/OS.cpp +++ b/src/OpenSHC/OS/OS.cpp @@ -157,5 +157,8 @@ namespace OS { return result; } + // STUB: STRONGHOLDCRUSADER 0x00580C0B + long __wtol(wchar_t const* str) { return _wtol(str); } + } } diff --git a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp new file mode 100644 index 0000000000..792efc7001 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp @@ -0,0 +1,352 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TextEditorState.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" + +namespace OpenSHC { +namespace Text { + + // TODO: fix L-strings + + // FUNCTION: STRONGHOLDCRUSADER 0x0045F5B0 + void TextEditorState::parseHlp() + { + FILE* filePointer[4]; + int graphicIndexes[4][100]; + + int const currentHelpSectionID = this->currentHelpSectionID; + int textMemIndex = 0; + + BOOL headerActive = FALSE; + BOOL bodyActive = FALSE; + int _filePointerIndex = 0; + + int loadedGraphics[4] = { 0, 0, 0, 0 }; + this->customHelpTextLength = 0; + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 40000, NULL, this->DAT_PointerToTemporaryTextMemory); + filePointer[0] = MACRO_CALL_MEMBER(TextEditorState_Func::readCrusaderHelpHlp, this)( + DAT_UserHelpDefinedData::instance.HelpSections[currentHelpSectionID]); + if (!filePointer[0]) { + return; + } + + while (_filePointerIndex >= 0) { + BOOL closeFile = FALSE; + while (!closeFile) { + int _wchar = MACRO_CALL(OS_Func::_fgetwc)(filePointer[_filePointerIndex]); + switch (_wchar) { + case '\n': + case '\r': + continue; + + case '<': { + wchar_t* hlpTag + = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(filePointer[_filePointerIndex]); + if (hlpTag) { + if (!MACRO_CALL(OS_Func::__wcsicmp)(L"header", hlpTag)) { + headerActive = TRUE; + continue; + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\header", hlpTag)) { + headerActive = FALSE; + continue; + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"body", hlpTag)) { + bodyActive = TRUE; + continue; + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\body", hlpTag)) { + bodyActive = FALSE; + continue; + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"loadpic", hlpTag)) { + if (headerActive) { + wchar_t* resourceName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (resourceName) { + char resourceNameChars[1000]; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteComplete, + DAT_WideCharMultiByteState::ptr)(resourceNameChars, resourceName); + + bool validPic = true; + if (!MACRO_CALL_MEMBER( + UI::Rendering::TextureRenderCore_Func::checkGfxResourceExists, + DAT_TextureRenderCoreObject::ptr)(resourceNameChars)) { + validPic = false; + } else if (!MACRO_CALL(OS_Func::__stricmp)( + resourceNameChars, "st99_dog_cage.tgx")) { + validPic = false; + } + if (!validPic) { + graphicIndexes[_filePointerIndex][loadedGraphics[_filePointerIndex]++] = -1; + } else { + graphicIndexes[_filePointerIndex][loadedGraphics[_filePointerIndex]++] + = MACRO_CALL_MEMBER(TextEditorState_Func::findOrAddHelpGraphicName, this)( + resourceNameChars); + } + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"pic", hlpTag)) { + if (bodyActive) { + wchar_t* picId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (picId) { + if (MACRO_CALL(OS_Func::__wtol)(picId) < loadedGraphics[_filePointerIndex]) { + if (graphicIndexes[_filePointerIndex][MACRO_CALL(OS_Func::__wtol)(picId)] + != -1) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_PIC; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = graphicIndexes[_filePointerIndex][MACRO_CALL(OS_Func::__wtol)(picId)]; + wchar_t* picPosition = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, + this)(filePointer[_filePointerIndex]); + if (!picPosition) { + closeFile = TRUE; + } else { + if (!MACRO_CALL(OS_Func::__wcsicmp)(L"left", picPosition)) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = HTT_PIC_LEFT; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"right", picPosition)) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = HTT_PIC_RIGHT; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"centre", picPosition)) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = HTT_PIC_CENTRE; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"here", picPosition)) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = HTT_PIC_HERE; + } + } + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_PIC; + continue; + } + } + if (!MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex])) { + closeFile = TRUE; + } + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"font", hlpTag)) { + if (bodyActive) { + wchar_t* fontId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (fontId) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_FONT; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = (short)MACRO_CALL(OS_Func::__wtol)(fontId); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_FONT; + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"colour", hlpTag)) { + if (bodyActive) { + wchar_t* colorId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (colorId) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_COLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = (short)MACRO_CALL(OS_Func::__wtol)(colorId); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_COLOUR; + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"linkcolour", hlpTag)) { + if (bodyActive) { + wchar_t* linkColorId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (linkColorId) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINKCOLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = (short)MACRO_CALL(OS_Func::__wtol)(linkColorId); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINKCOLOUR; + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"link", hlpTag)) { + if (bodyActive) { + wchar_t* linkName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (linkName) { + char linkNameChars[1000]; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteComplete, + DAT_WideCharMultiByteState::ptr)(linkNameChars, linkName); + int const helpSectionIndex = MACRO_CALL_MEMBER( + TextEditorState_Func::findOrAddHelpSectionName, this)(linkNameChars); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINK; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = helpSectionIndex; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINK; + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\link", hlpTag)) { + if (bodyActive) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_ENDLINK; + continue; + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"newparagraph", hlpTag)) { + if (bodyActive) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_NEWPARAGRAPH; + continue; + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"centre", hlpTag)) { + if (bodyActive) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_CENTRE; + continue; + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\centre", hlpTag)) { + if (bodyActive) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_ENDCENTRE; + continue; + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"sound", hlpTag)) { + if (bodyActive) { + wchar_t* soundName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (soundName) { + char soundNameChars[1000]; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteComplete, + DAT_WideCharMultiByteState::ptr)(soundNameChars, soundName); + int const soundIndex = MACRO_CALL_MEMBER( + TextEditorState_Func::findOrAddSoundName, this)(soundNameChars); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_SOUND; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = soundIndex; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_SOUND; + continue; + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"include", hlpTag)) { + if (bodyActive) { + if (DAT_TextEditorState::instance.useAlternateHelpTab) { + wchar_t* includeName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (includeName) { + char includeNameChars[1000]; + MACRO_CALL_MEMBER( + Util::WideCharMultiByteState_Func::wideCharToMultiByteComplete, + DAT_WideCharMultiByteState::ptr)(includeNameChars, includeName); + int const helpSectionIndex = MACRO_CALL_MEMBER( + TextEditorState_Func::findOrAddHelpSectionName, this)(includeNameChars); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_INCLUDE; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = helpSectionIndex; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_INCLUDE; + continue; + } + } else { + wchar_t* includeName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (includeName) { + char includeNameChars[1000]; + MACRO_CALL_MEMBER( + Util::WideCharMultiByteState_Func::wideCharToMultiByteComplete, + DAT_WideCharMultiByteState::ptr)(includeNameChars, includeName); + int sectionId = MACRO_CALL_MEMBER( + TextEditorState_Func::findOrAddHelpSectionName, this)(includeNameChars); + ++_filePointerIndex; + bodyActive = FALSE; + headerActive = FALSE; + loadedGraphics[_filePointerIndex] = 0; + filePointer[_filePointerIndex] + = MACRO_CALL_MEMBER(TextEditorState_Func::readCrusaderHelpHlp, this)( + DAT_UserHelpDefinedData::instance.HelpSections[sectionId]); + continue; + } + } + } + + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"string", hlpTag)) { + if (bodyActive) { + wchar_t* stringId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( + filePointer[_filePointerIndex]); + if (stringId) { + if (this->helpDialogVariant) { + long const textIndex = MACRO_CALL(OS_Func::__wtol)(stringId); + + if (this->intArray1[textIndex]) { + int i = 0; + // Mismatch: wrong order of ptr access addition + while (this->intArray1[textIndex][i]) { + wchar_t const ch = this->intArray1[textIndex][i++]; + if (ch == L'\n') { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = HTT_NEWPARAGRAPH; + } else if (ch >= L' ') { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = ch; + } + } + } + + } else { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_STRING; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] + = (short)MACRO_CALL(OS_Func::__wtol)(stringId); + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_STRING; + } + continue; + } + } + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\section", hlpTag)) { + closeFile = TRUE; + continue; + } else { + continue; + } + } + + closeFile = TRUE; + continue; + } + + case L'\u2019': // ’ + _wchar = L'`'; + break; + + case L'\u201C': // “ + case L'\u201D': // ” + _wchar = L'"'; + break; + + case WEOF: + closeFile = TRUE; + continue; + + default: + break; + } + + if (bodyActive) { + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = _wchar; + } + }; + + MACRO_CALL(OS_Func::_fclose)(filePointer[_filePointerIndex]); + bodyActive = TRUE; + headerActive = FALSE; + --_filePointerIndex; + } + this->customHelpTextLength = textMemIndex; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 78fedf7d06..5ba701b3fc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18757,7 +18757,7 @@ SHC_3BB0A8C1_0x0045F470 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F580 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0045F5B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F5B0 | 99.0% | Reimplemented, two cases where an "edx + ecx" is flipped to "ecx + edx" SHC_3BB0A8C1_0x0045FDC0 | 0.0% | Pending From 64faf8fb29fa8ee981314eac1f01aa0373f004de Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:29:18 +0200 Subject: [PATCH 29/44] reimplement: SHC_3BB0A8C1_0x004614D0 100% --- src/OpenSHC/Text/TextEditorState.hpp | 6 +++++ .../initializeAndLayoutHelpText.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 5c547d91c6..13440b2052 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -20,6 +20,12 @@ namespace OpenSHC { namespace Text { + struct LineLayout { + short unknown0; + short unknown1; + short unknown2; + }; + using OpenSHC::Text::ImageHotspot; using OpenSHC::Text::LineLayout; using OpenSHC::Text::Enums::HelpTextToken; diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp new file mode 100644 index 0000000000..44b86a79ce --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp @@ -0,0 +1,22 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x004614D0 + void TextEditorState::initializeAndLayoutHelpText() + { + for (int i = 0; i < 20000; ++i) { + this->lineLayoutTable[i].unknown0 = 25; + this->lineLayoutTable[i].unknown1 = this->dialogContentHeight - 25; + this->lineLayoutTable[i].unknown2 = 0; + } + for (int i = 0; i < 4; ++i) { + this->lineLayoutTable[i].unknown0 = -1; + } + this->imageHotspotCount = 0; + while (!MACRO_CALL_MEMBER(TextEditorState_Func::processHelpRichTextTokens, this)(0)) {}; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5ba701b3fc..e37e588e42 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18827,7 +18827,7 @@ SHC_3BB0A8C1_0x004613D4 | 0.0% | Pending SHC_3BB0A8C1_0x004613E0 | 0.0% | Pending -SHC_3BB0A8C1_0x004614D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004614D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004614F0 | 0.0% | Pending From 427813f631b4e65d5c53d70113197fda4de6e258 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:37:25 +0200 Subject: [PATCH 30/44] reimplement: SHC_3BB0A8C1_0x004613E0 100% --- .../TextEditorState/setTextRenderingLogic.cpp | 55 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp diff --git a/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp b/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp new file mode 100644 index 0000000000..72ef3128de --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp @@ -0,0 +1,55 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" + +#include "OpenSHC/Globals/DAT_PencilRenderCore.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x004613E0 + void TextEditorState::setTextRenderingLogic() + { + if (this->helpDialogVariant != 1) { + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRect, + DAT_TextureRenderCoreObject::ptr)(this->dialogContentX, this->dialogContentY, + this->dialogContentHeight + this->dialogContentX, this->dialogContentWidth + this->dialogContentY); + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setScreenMenuSurfaceHeightRange, + DAT_TextureRenderCoreObject::ptr)( + this->dialogContentY, this->dialogContentWidth + this->dialogContentY); + DAT_TextureRenderCoreObject::instance.drawBufferChoiceValue = Rendering::Enums::RT_SCREEN_MENU; + } else { + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRect, + DAT_TextureRenderCoreObject::ptr)(this->dialogContentX, this->dialogContentY, + this->dialogContentHeight + this->dialogContentX, this->dialogContentWidth + this->dialogContentY); + MACRO_CALL_MEMBER( + UI::Rendering::TextureRenderCore_Func::setMapSurfaceHeightRange, DAT_TextureRenderCoreObject::ptr)( + this->dialogContentY, this->dialogContentWidth + this->dialogContentY); + DAT_TextManagerObject::instance.textSurfaceTarget = Rendering::Enums::RT_MAP_GAME; + DAT_PencilRenderCore::instance.surfaceTarget = Rendering::Enums::RT_MAP_GAME; + DAT_TextureRenderCoreObject::instance.currentRenderSurfaceIdentifierUnk_0x8 = Rendering::Enums::RT_MAP_GAME; + } + MACRO_CALL_MEMBER(TextEditorState_Func::processHelpRichTextTokens, this)(TRUE); + MACRO_CALL_MEMBER(TextEditorState_Func::renderHelpImageHotspots, this)(); + if (this->helpDialogVariant != 1) { + DAT_TextureRenderCoreObject::instance.drawBufferChoiceValue = Rendering::Enums::RT_MAP_GAME; + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setScreenMenuSurfaceHeightRangeToResolution, + DAT_TextureRenderCoreObject::ptr)(); + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRectToGameResolution, + DAT_TextureRenderCoreObject::ptr)(); + } else { + MACRO_CALL_MEMBER( + UI::Rendering::TextureRenderCore_Func::setMapSurfaceHeightRangeUnk, DAT_TextureRenderCoreObject::ptr)(); + MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRectToGameResolution, + DAT_TextureRenderCoreObject::ptr)(); + DAT_TextManagerObject::instance.textSurfaceTarget = Rendering::Enums::RT_SCREEN_MENU; + DAT_PencilRenderCore::instance.surfaceTarget = Rendering::Enums::RT_SCREEN_MENU; + DAT_TextureRenderCoreObject::instance.currentRenderSurfaceIdentifierUnk_0x8 + = Rendering::Enums::RT_SCREEN_MENU; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e37e588e42..f6691c3956 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18825,7 +18825,7 @@ SHC_3BB0A8C1_0x004613D0 | 0.0% | Pending SHC_3BB0A8C1_0x004613D4 | 0.0% | Pending -SHC_3BB0A8C1_0x004613E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004613E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004614D0 | 100.0% | Reimplemented From 2efc138375b4e3f8e4b55868a83eedf6c38f62cc Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:42:26 +0200 Subject: [PATCH 31/44] reimplement: SHC_3BB0A8C1_0x00461550 100% --- .../TextEditorState/renderHelpDialogIfOpen.cpp | 16 ++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/renderHelpDialogIfOpen.cpp diff --git a/src/OpenSHC/Text/TextEditorState/renderHelpDialogIfOpen.cpp b/src/OpenSHC/Text/TextEditorState/renderHelpDialogIfOpen.cpp new file mode 100644 index 0000000000..13ff6f4a48 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/renderHelpDialogIfOpen.cpp @@ -0,0 +1,16 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461550 + void TextEditorState::renderHelpDialogIfOpen() + { + if (this->isDialogStateInitialized) { + MACRO_CALL_MEMBER(TextEditorState_Func::drawHelpWindowBackground, this)(); + MACRO_CALL_MEMBER(TextEditorState_Func::setTextRenderingLogic, this)(); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f6691c3956..405a627c23 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18833,7 +18833,7 @@ SHC_3BB0A8C1_0x004614F0 | 0.0% | Pending SHC_3BB0A8C1_0x00461520 | 0.0% | Pending -SHC_3BB0A8C1_0x00461550 | 0.0% | Pending +SHC_3BB0A8C1_0x00461550 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461570 | 0.0% | Pending From 16c035eae75265955a69d6e11e823c2b4b2874a4 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:45:55 +0200 Subject: [PATCH 32/44] reimplement: SHC_3BB0A8C1_0x004619D0 100% --- .../loadAndLayoutHelpContent.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp diff --git a/src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp b/src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp new file mode 100644 index 0000000000..62a5eddb7d --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp @@ -0,0 +1,22 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x004619D0 + void TextEditorState::loadAndLayoutHelpContent() + { + this->graphicFileCount = 0; + this->soundFileCount = 0; + this->topVisibleLineIndex = -1; + this->helpContentScrollOffsetY = 0; + if (!this->isCustomTextMode) { + MACRO_CALL_MEMBER(TextEditorState_Func::parseHlp, this)(); + MACRO_CALL_MEMBER(TextEditorState_Func::loadHelpSectionGraphics, this)(); + } + this->activeHelpHotspotIndex = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::initializeAndLayoutHelpText, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 405a627c23..c9347363cc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18879,7 +18879,7 @@ SHC_3BB0A8C1_0x004619C4 | 0.0% | Pending SHC_3BB0A8C1_0x004619C8 | 0.0% | Pending -SHC_3BB0A8C1_0x004619D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004619D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461A20 | 0.0% | Pending From 6e32ff366c1d5aa839b5faabbf6c0609c0c01a25 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 16:24:34 +0200 Subject: [PATCH 33/44] reimplement: SHC_3BB0A8C1_0x00461A20 100% --- .../openBuildingHelpDialog.cpp | 79 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp new file mode 100644 index 0000000000..fd849ca465 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp @@ -0,0 +1,79 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Text/TextEditorState.func.hpp" +#include "OpenSHC/UI/MenuModalComposition.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461A20 + void TextEditorState::openBuildingHelpDialog(int sectionId) + { + if (!this->isDialogStateInitialized) { + this->isDialogStateInitialized = TRUE; + this->helpDialogVariant = 1; + this->useInGameHelpHandler = 0; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = 0; + this->isCustomTextMode = 0; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + this->helpContentScrollX = 0; + this->helpContentScrollY = 0; + } else if (sectionId == this->currentHelpSectionID) { + return; + } + + this->activeHelpHotspotIndex = 0; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + + this->isTextHelpDialogMode = 1; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_BUILDING_HELP_TEXT, FALSE); + + int modalX; + int modalY; + int modalWidth; + int modalHeight; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::fillWithMenuModalDimensions, DAT_MenuModalComposition1::ptr)( + &modalX, &modalY, &modalWidth, &modalHeight); + // Likely also some rect structure + DAT_00df2964::instance = 15; + DAT_00df296c::instance = 13; + INT_00df2968::instance = 60; + INT_00df2970::instance = 65; + this->dialogX = modalX; + this->dialogY = modalY; + this->dialogWidth = modalWidth; + this->dialogHeight = modalHeight; + + int const dialogContentX = this->dialogX + DAT_00df2964::instance; + int const dialogContentY = this->dialogY + DAT_00df296c::instance; + int const dialogContentHeight = this->dialogHeight - INT_00df2970::instance; + int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = dialogContentX; + this->dialogContentY = dialogContentY; + this->dialogContentHeight = dialogContentWidth; + this->dialogContentWidth = dialogContentHeight; + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = sectionId; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c9347363cc..1c377d3747 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18881,7 +18881,7 @@ SHC_3BB0A8C1_0x004619C8 | 0.0% | Pending SHC_3BB0A8C1_0x004619D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00461A20 | 0.0% | Pending +SHC_3BB0A8C1_0x00461A20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461B90 | 0.0% | Pending From f994a66250cebc923a8aeade1c7ff97c8cc9333d Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 18:58:52 +0200 Subject: [PATCH 34/44] reimplement: SHC_3BB0A8C1_0x00461B90 100% --- .../TextEditorState/openInGameHelpDialog.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp new file mode 100644 index 0000000000..cdb41b1d71 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp @@ -0,0 +1,74 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/MenuModalComposition.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461B90 + void TextEditorState::openInGameHelpDialog(int sectionId) + { + if (!this->isDialogStateInitialized) { + this->isDialogStateInitialized = TRUE; + this->helpDialogVariant = 1; + this->useInGameHelpHandler = TRUE; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = 0; + this->isCustomTextMode = 0; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + this->helpContentScrollX = 0; + this->helpContentScrollY = 0; + } + this->activeHelpHotspotIndex = 0; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + this->isTextHelpDialogMode = TRUE; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_IN_GAME_HELP_TEXT, FALSE); + + int modalX; + int modalY; + int modalWidth; + int modalHeight; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::fillWithMenuModalDimensions, DAT_MenuModalComposition1::ptr)( + &modalX, &modalY, &modalWidth, &modalHeight); + + DAT_00df2964::instance = 15; + DAT_00df296c::instance = 13; + INT_00df2968::instance = 60; + INT_00df2970::instance = 65; + this->dialogX = modalX; + this->dialogY = modalY; + this->dialogWidth = modalWidth; + this->dialogHeight = modalHeight; + + int const dialogContentX = this->dialogX + DAT_00df2964::instance; + int const dialogContentY = this->dialogY + DAT_00df296c::instance; + int const dialogContentHeight = this->dialogHeight - INT_00df2970::instance; + int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = dialogContentX; + this->dialogContentY = dialogContentY; + this->dialogContentHeight = dialogContentWidth; + this->dialogContentWidth = dialogContentHeight; + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = sectionId; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1c377d3747..73ac6429c7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18883,7 +18883,7 @@ SHC_3BB0A8C1_0x004619D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461A20 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00461B90 | 0.0% | Pending +SHC_3BB0A8C1_0x00461B90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461CF0 | 0.0% | Pending From 803645d729ab36d5141fd6254654ff920d0be773 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:05:09 +0200 Subject: [PATCH 35/44] reimplement: SHC_3BB0A8C1_0x00461CF0 100% --- .../openScenarioHelpDialog.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp new file mode 100644 index 0000000000..cbe2b44f4b --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp @@ -0,0 +1,74 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/MenuModalComposition.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461CF0 + void TextEditorState::openScenarioHelpDialog(int sectionId) + { + if (!this->isDialogStateInitialized) { + this->isDialogStateInitialized = TRUE; + this->helpDialogVariant = 2; + this->useInGameHelpHandler = FALSE; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = FALSE; + this->isCustomTextMode = FALSE; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + this->helpContentScrollX = 0; + this->helpContentScrollY = 0; + } + this->activeHelpHotspotIndex = 0; + if (sectionId == -1) { + MACRO_CALL_MEMBER(OpenSHC::Text::TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + this->isTextHelpDialogMode = TRUE; + MACRO_CALL_MEMBER(OpenSHC::UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + OpenSHC::UI::Enums::MMT_DISPLAY_SCENARIO_HELP_TEXT, FALSE); + + int modalX; + int modalY; + int modalWidth; + int modalHeight; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::fillWithMenuModalDimensions, DAT_MenuModalComposition1::ptr)( + &modalX, &modalY, &modalWidth, &modalHeight); + + DAT_00df2964::instance = 10; + DAT_00df296c::instance = 10; + INT_00df2968::instance = 45; + INT_00df2970::instance = 20; + this->dialogX = modalX; + this->dialogY = modalY; + this->dialogWidth = modalWidth; + this->dialogHeight = modalHeight; + + int const dialogContentX = this->dialogX + DAT_00df2964::instance; + int const dialogContentY = this->dialogY + DAT_00df296c::instance; + int const dialogContentHeight = this->dialogHeight - INT_00df2970::instance; + int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = dialogContentX; + this->dialogContentY = dialogContentY; + this->dialogContentHeight = dialogContentWidth; + this->dialogContentWidth = dialogContentHeight; + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = sectionId; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(OpenSHC::Text::TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 73ac6429c7..b723b042d9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18885,7 +18885,7 @@ SHC_3BB0A8C1_0x00461A20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461B90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00461CF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00461CF0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461E50 | 0.0% | Pending From 92db2d4d2bd0b9b85b6768b372076c516646e3a3 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:10:11 +0200 Subject: [PATCH 36/44] reimplement: SHC_3BB0A8C1_0x00461E50 100% --- .../openCreditsScrollDialog.cpp | 73 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp b/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp new file mode 100644 index 0000000000..cc8d182e5f --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp @@ -0,0 +1,73 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/MenuModalComposition.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461E50 + void TextEditorState::openCreditsScrollDialog(int sectionId) + { + if (!this->isDialogStateInitialized) { + this->isDialogStateInitialized = TRUE; + this->helpDialogVariant = 2; + this->useInGameHelpHandler = FALSE; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = FALSE; + this->isCustomTextMode = FALSE; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + } + this->activeHelpHotspotIndex = 0; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + + this->isTextHelpDialogMode = TRUE; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_CREDITS_SCROLL, FALSE); + + int modalX; + int modalY; + int modalWidth; + int modalHeight; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::fillWithMenuModalDimensions, DAT_MenuModalComposition1::ptr)( + &modalX, &modalY, &modalWidth, &modalHeight); + + DAT_00df2964::instance = 0; + DAT_00df296c::instance = 0; + INT_00df2968::instance = 0; + INT_00df2970::instance = 0; + this->dialogX = modalX; + this->dialogY = modalY; + this->dialogWidth = modalWidth; + this->dialogHeight = modalHeight; + + int const dialogContentX = this->dialogX + DAT_00df2964::instance; + int const dialogContentY = this->dialogY + DAT_00df296c::instance; + int const dialogContentHeight = this->dialogHeight - INT_00df2970::instance; + int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = dialogContentX; + this->dialogContentY = dialogContentY; + this->dialogContentHeight = dialogContentWidth; + this->dialogContentWidth = dialogContentHeight; + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = sectionId; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b723b042d9..2bd61b0ed7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18887,7 +18887,7 @@ SHC_3BB0A8C1_0x00461B90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461CF0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00461E50 | 0.0% | Pending +SHC_3BB0A8C1_0x00461E50 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461F90 | 0.0% | Pending From 77c6a8ce18e10749d23b378a239d8845f1446551 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:14:43 +0200 Subject: [PATCH 37/44] reimplement: SHC_3BB0A8C1_0x00461F90 100% --- .../openMapDescriptionEditorDialog.cpp | 75 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp b/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp new file mode 100644 index 0000000000..ab6933b088 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp @@ -0,0 +1,75 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/UI/MenuModalComposition.func.hpp" + +#include "OpenSHC/Globals/DAT_00df2964.hpp" +#include "OpenSHC/Globals/DAT_00df296c.hpp" +#include "OpenSHC/Globals/DAT_MenuModalComposition1.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/INT_00df2968.hpp" +#include "OpenSHC/Globals/INT_00df2970.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00461F90 + void TextEditorState::openMapDescriptionEditorDialog(int sectionId) + { + if (!this->isDialogStateInitialized) { + this->isDialogStateInitialized = TRUE; + this->helpDialogVariant = 0; + this->useInGameHelpHandler = FALSE; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = TRUE; + this->isCustomTextMode = TRUE; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + this->helpContentScrollX = 0; + this->helpContentScrollY = 0; + } + this->activeHelpHotspotIndex = 0; + this->customHelpTextPointer = NULL; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + this->isTextHelpDialogMode = 0; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::activateModalDialog, DAT_MenuModalComposition1::ptr)( + UI::Enums::MMT_MAP_DESCRIPTION_EDITOR, FALSE); + + int modalX; + int modalY; + int modalWidth; + int modalHeight; + MACRO_CALL_MEMBER(UI::MenuModalComposition_Func::fillWithMenuModalDimensions, DAT_MenuModalComposition1::ptr)( + &modalX, &modalY, &modalWidth, &modalHeight); + + DAT_00df2964::instance = 10; + DAT_00df296c::instance = 10; + INT_00df2968::instance = 45; + INT_00df2970::instance = 53; + this->dialogX = modalX; + this->dialogY = modalY; + this->dialogWidth = modalWidth; + this->dialogHeight = modalHeight; + + int const dialogContentX = this->dialogX + DAT_00df2964::instance; + int const dialogContentY = this->dialogY + DAT_00df296c::instance; + int const dialogContentHeight = this->dialogHeight - INT_00df2970::instance; + int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; + this->dialogContentX = dialogContentX; + this->dialogContentY = dialogContentY; + this->dialogContentHeight = dialogContentWidth; + this->dialogContentWidth = dialogContentHeight; + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = -1; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2bd61b0ed7..56b0dce0c5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18889,7 +18889,7 @@ SHC_3BB0A8C1_0x00461CF0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461E50 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00461F90 | 0.0% | Pending +SHC_3BB0A8C1_0x00461F90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004620F0 | 0.0% | Pending From bba5eba600d45e8e4b81ff4d653ad4ceb3aee9eb Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:21:41 +0200 Subject: [PATCH 38/44] reimplement: SHC_3BB0A8C1_0x004620F0 100% --- .../TextEditorState/setCustomHelpText.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp diff --git a/src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp b/src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp new file mode 100644 index 0000000000..83c6495a62 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp @@ -0,0 +1,24 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" + +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x004620F0 + void TextEditorState::setCustomHelpText(char* helpText, int bufferSize) + { + this->customHelpTextPointer = helpText; + this->isCustomHelpTextWide = 0; + this->customHelpTextBufferSize = bufferSize; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharacter, DAT_WideCharMultiByteState::ptr)( + this->DAT_PointerToTemporaryTextMemory, helpText); + this->customHelpTextLength = strlen(helpText); + this->isTextHelpDialogMode = TRUE; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 56b0dce0c5..7289b8b391 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18891,7 +18891,7 @@ SHC_3BB0A8C1_0x00461E50 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00461F90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004620F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004620F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00462150 | 0.0% | Pending From 7b962143088f201b72a2444c3a08d4cce48ad365 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 19:28:52 +0200 Subject: [PATCH 39/44] reimplement: SHC_3BB0A8C1_0x00462150 100% --- .../TextEditorState/popHelpDialogStack.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Text/TextEditorState/popHelpDialogStack.cpp diff --git a/src/OpenSHC/Text/TextEditorState/popHelpDialogStack.cpp b/src/OpenSHC/Text/TextEditorState/popHelpDialogStack.cpp new file mode 100644 index 0000000000..5fd6604c00 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/popHelpDialogStack.cpp @@ -0,0 +1,25 @@ +#include "../TextEditorState.func.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00462150 + void TextEditorState::popHelpDialogStack() + { + int sectionId = this->helpSectionHistoryStack[0]; + + for (int i = 0; i < 29; ++i) { + this->helpSectionHistoryStack[i] = this->helpSectionHistoryStack[i + 1]; + } + this->helpSectionHistoryStack[29] = -1; + + this->currentHelpSectionID = sectionId; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + } else { + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7289b8b391..23b32bdd58 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18893,7 +18893,7 @@ SHC_3BB0A8C1_0x00461F90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004620F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00462150 | 0.0% | Pending +SHC_3BB0A8C1_0x00462150 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00462190 | 0.0% | Pending From b07dbc0dc9fc49ab2b3ab0af0916595bfd0710f5 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 17 Sep 2026 20:11:51 +0200 Subject: [PATCH 40/44] reimplement: SHC_3BB0A8C1_0x00462190 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../openUnusedHelpTextEditorDialog.cpp | 95 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 13440b2052..2f904d89c1 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -178,7 +178,7 @@ namespace Text { void popHelpDialogStack(); - void openUnusedHelpTextEditorDialog(int param_1); + void openUnusedHelpTextEditorDialog(int sectionId); }; static_assert_cpp98_obj(sizeof(TextEditorState) == 145780, TextEditorState); diff --git a/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp b/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp new file mode 100644 index 0000000000..45951bd8d2 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp @@ -0,0 +1,95 @@ +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" +#include "OpenSHC/Globals/Menu_UnusedHelpTextEditor.hpp" + +namespace OpenSHC { +namespace Text { + + // FUNCTION: STRONGHOLDCRUSADER 0x00462190 + void TextEditorState::openUnusedHelpTextEditorDialog(int sectionId) + { + if (this->helpDialogVariant) { + if (this->helpDialogVariant == 2) { + MACRO_CALL_MEMBER(TextEditorState_Func::openScenarioHelpDialog, this)(sectionId); + return; + } + if (this->useInGameHelpHandler) { + MACRO_CALL_MEMBER(TextEditorState_Func::openInGameHelpDialog, this)(sectionId); + return; + } + MACRO_CALL_MEMBER(TextEditorState_Func::openBuildingHelpDialog, this)(sectionId); + return; + } + + if (!this->isDialogStateInitialized) { + this->savedMenuViewType = DAT_GameCore::instance.currentMenuViewType; + this->savedActiveMenuTab = DAT_GameCore::instance.activeMenuTab.tabType; + this->savedMenuFlag = DAT_GameCore::instance.unknownAlwaysZero01; + this->unknown_0x23960 = 1; + this->isDialogStateInitialized = TRUE; + this->useInGameHelpHandler = FALSE; + this->helpDialogVariant = 0; + this->helpDialogSubMode = 0; + this->useAlternateHelpTab = FALSE; + this->isCustomTextMode = FALSE; + this->helpContentScrollX = 0; + this->helpContentScrollY = 0; + this->useWideHelpLayout = FALSE; + DAT_UserTextHandlerState::instance.inputBufferIndex = 0; + } + this->activeHelpHotspotIndex = 0; + if (sectionId == -1) { + MACRO_CALL_MEMBER(TextEditorState_Func::closeHelpDialogAndReturnToMenu, this)(); + return; + } + if (!this->useAlternateHelpTab) { + this->isTextHelpDialogMode = TRUE; + DAT_GameCore::instance.menuTabToSwitchTo.tabType = 0; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + UI::Enums::MVT_UNUSED_HELP_TEXT_EDITOR, 0); + } else { + this->isTextHelpDialogMode = TRUE; + DAT_GameCore::instance.menuTabToSwitchTo.tabType = 1; + MACRO_CALL_MEMBER(Game::GameCore_Func::switchToMenuView, DAT_GameCore::ptr)( + UI::Enums::MVT_UNUSED_HELP_TEXT_EDITOR, 0); + } + Menu_UnusedHelpTextEditor::instance.thousand = 0; + + int const dialogX = DAT_WindowAndDirectDraw::instance.mainMenuBorderWidth + 80; + int const dialogY = DAT_WindowAndDirectDraw::instance.mainMenuBorderHeight + 60; + int const dialogWidth = 640; + int const dialogHeight = 480; + this->dialogX = dialogX; + this->dialogY = dialogY; + this->dialogWidth = dialogWidth; + this->dialogHeight = dialogHeight; + + if (!this->useWideHelpLayout) { + this->dialogContentX = this->dialogX + 10; + this->dialogContentY = this->dialogY + 10; + this->dialogContentHeight = 600; + this->dialogContentWidth = 435; + } else { + this->dialogContentX = this->dialogX + 10; + this->dialogContentY = this->dialogY + 10; + this->dialogContentHeight = 664; + this->dialogContentWidth = 291; + } + + for (int i = 28; i >= 0; --i) { + this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; + } + this->helpSectionHistoryStack[0] = this->currentHelpSectionID; + + this->currentHelpSectionID = sectionId; + this->helpContentScrollOffsetY = 0; + MACRO_CALL_MEMBER(TextEditorState_Func::loadAndLayoutHelpContent, this)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 23b32bdd58..91ba63d60a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18895,7 +18895,7 @@ SHC_3BB0A8C1_0x004620F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00462150 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00462190 | 0.0% | Pending +SHC_3BB0A8C1_0x00462190 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00462340 | 0.0% | Pending From 8c299e74f1afc86b31a9af0463f7c39da6bb941d Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sat, 19 Sep 2026 00:19:43 +0200 Subject: [PATCH 41/44] reimplement: SHC_3BB0A8C1_0x0045FDC0 buildable, horrible match --- IMPLEMENTATION_CHEAT_SHEET.md | 49 +- src/OpenSHC/Text/TextEditorState.hpp | 9 +- .../initializeAndLayoutHelpText.cpp | 7 +- .../processHelpRichTextTokens.cpp | 815 ++++++++++++++++++ 4 files changed, 857 insertions(+), 23 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 6a19c9856d..afc4ac6615 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -545,25 +545,36 @@ They are replaced by specific assembly instructions or otherwise inlined. A list of all intrinsics can be found in `intrin.h` in the std library, but these are mainly very low level instructions. However, there are also C functions that can be replaced by intrinsics. The following attempts to extract these from the header: -| Intrinsic | Does | -| --------- | ---------------------------------------------------------------------------------------------- | -| `memcpy` | Copies a memory block. **Does not support overlapping regions** (use `memmove` for overlap). | -| `memset` | Fills a memory block with a byte value. | -| `memcmp` | Compares two memory blocks byte-by-byte. | -| `memchr` | Searches memory for the first occurrence of a byte. | -| `strcpy` | Copies a null-terminated C string. | -| `strlen` | Returns the length of a null-terminated string (excluding `\0`). | -| `strcmp` | Compares two null-terminated C strings. | -| `strcat` | Appends one null-terminated C string to another. | -| `strncpy` | Copies up to N characters from a string; **may not null-terminate** if the source is too long. | -| `strncmp` | Compares up to N characters of two strings. | -| `wcscpy` | Copies a null-terminated wide-character string. | -| `wcslen` | Returns the length of a null-terminated wide string. | -| `ceil` | Rounds a floating-point value upward to the nearest integer value. | -| `abs` | Returns the absolute value of an `int`. | -| `labs` | Returns the absolute value of a `long`. | -| `longjmp` | Restores a saved execution context created by `setjmp`, continuing execution from that point. | -| `_setjmp` | Saves the current execution context for later restoration with `longjmp`. | +| Intrinsic | Does | +|---------------------------|----------------------------------------------------------------------------------------------------------------------| +| `memcpy` | Copies a memory block. **Does not support overlapping regions** (use `memmove` for overlap). | +| `memset` | Fills a memory block with a byte value. | +| `memcmp` | Compares two memory blocks byte-by-byte. | +| `memchr` | Searches memory for the first occurrence of a byte. | +| `strcpy` | Copies a null-terminated C string. | +| `strlen` | Returns the length of a null-terminated string (excluding `\0`). | +| `strcmp` | Compares two null-terminated C strings. | +| `strcat` | Appends one null-terminated C string to another. | +| `strncpy` | Copies up to N characters from a string; **may not null-terminate** if the source is too long. | +| `strncmp` | Compares up to N characters of two strings. | +| `strset` | Sets every character in a null-terminated string to the specified character. | +| `_strset` | Microsoft-specific version of `strset`; sets every character in a null-terminated string to the specified character. | +| `wcscpy` | Copies a null-terminated wide-character string. | +| `wcslen` | Returns the length of a null-terminated wide string. | +| `wcscmp` | Compares two null-terminated wide-character strings. | +| `wcscat` | Appends one null-terminated wide-character string to another. | +| `wcsncpy` | Copies up to N wide characters; **may not null-terminate** if the source is too long. | +| `wcsncmp` | Compares up to N wide characters of two strings. | +| `_wcsset` | Sets every character in a null-terminated wide string to the specified wide character. | +| `ceil` | Returns the smallest integral floating-point value greater than or equal to the argument. | +| `abs` | Returns the absolute value of an `int`. | +| `labs` | Returns the absolute value of a `long`. | +| `longjmp` | Restores a saved execution context created by `setjmp`, continuing execution from that point. | +| `_setjmp` | Saves the current execution context for later restoration with `longjmp`. | +| `_AddressOfReturnAddress` | Returns the address of the current function's return-address storage. | +| `_WriteBarrier` | Prevents certain compiler memory-write reorderings across the barrier. | +| `__trap` | Generates a processor/compiler trap, optionally with arguments. | + In cases where the decompiler seems to perform one of these actions via simple instructions, one can also try one of these functions. diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 2f904d89c1..be0f30e8e0 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -20,6 +20,13 @@ namespace OpenSHC { namespace Text { + struct ImageHotspot { + short xPos; + short yPos; + short imageRelated; + short unknown3; + }; + struct LineLayout { short unknown0; short unknown1; @@ -178,7 +185,7 @@ namespace Text { void popHelpDialogStack(); - void openUnusedHelpTextEditorDialog(int sectionId); + void openUnusedHelpTextEditorDialog(int param_1); }; static_assert_cpp98_obj(sizeof(TextEditorState) == 145780, TextEditorState); diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp index 44b86a79ce..99fef53e0f 100644 --- a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp +++ b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp @@ -7,12 +7,13 @@ namespace Text { void TextEditorState::initializeAndLayoutHelpText() { for (int i = 0; i < 20000; ++i) { - this->lineLayoutTable[i].unknown0 = 25; - this->lineLayoutTable[i].unknown1 = this->dialogContentHeight - 25; + this->lineLayoutTable[i].leftBorder = 25; + this->lineLayoutTable[i].rightBorder = this->dialogContentHeight - 25; this->lineLayoutTable[i].unknown2 = 0; } + // Adds vertical space at start for (int i = 0; i < 4; ++i) { - this->lineLayoutTable[i].unknown0 = -1; + this->lineLayoutTable[i].leftBorder = -1; } this->imageHotspotCount = 0; while (!MACRO_CALL_MEMBER(TextEditorState_Func::processHelpRichTextTokens, this)(0)) {}; diff --git a/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp new file mode 100644 index 0000000000..837af17dd5 --- /dev/null +++ b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp @@ -0,0 +1,815 @@ +// disable deprecation warnings for wcscpy and wcscat +#pragma warning(disable : 4996) + +#include "../TextEditorState.func.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Input/MouseState.func.hpp" +#include "OpenSHC/Text/FontSizeClass.func.hpp" +#include "OpenSHC/UI/Rendering/PencilRenderCore.func.hpp" + +#include "OpenSHC/Globals/COL_DARK_LIME.hpp" +#include "OpenSHC/Globals/DAT_00df3348.hpp" +#include "OpenSHC/Globals/DAT_00df334c.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" +#include "OpenSHC/Globals/DAT_PencilRenderCore.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" +#include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" + +namespace OpenSHC { +namespace Text { + + union TextMemUnion { + int value; + wchar_t* text; + HelpTextToken helpToken; + HelpTextPicturePositionToken picturePositionToken; + }; + + // FUNCTION: STRONGHOLDCRUSADER 0x0045FDC0 + int TextEditorState::processHelpRichTextTokens(int param_1) + { + int iVar5; + wchar_t* pwVar6; + int iVar12; + int dVar14; + int iVar17; + int local_12c; + int local_118; + int local_114; + int local_104; + int local_f8; + int local_f4; + wchar_t wideTextBuffer[100]; + int currentLinkId = -1; + int textMemIndex = 0; + FontSizeClass* currentFontClass = DAT_TextManagerObject::instance.fontSizeClassArray + 17; + int currentFontLineHeight = DAT_TextManagerObject::instance.fontSizeClassArray[17].lineHeight_0x14; + BOOL local_f0 = FALSE; + BGR24 color = 0xccfaff; + BGR24 linkColor = 0x8bcf84; + int imageCount = -1; + BOOL centreActive = FALSE; + BOOL local_120 = FALSE; + int lineStartY = 0; + int lineEndY = 0; + int local_11c = 0; + int local_100 = 0; + int local_10c = 0; + BOOL local_e4 = FALSE; + int local_134 = -10000; + if (this->helpDialogVariant == 2 || this->isCustomTextMode) { + color = 0xc2f0eb; + } + if (!this->isTextHelpDialogMode) { + return 1; + } + this->unknown_0x23964 = -1; + this->unknown_0x23968 = -1; + if (this->unknown_0x2396C) { + DAT_00df334c::instance = 1; + } + if (this->activeHelpHotspotIndex < 0) { + this->activeHelpHotspotIndex = 0; + } + if (this->activeHelpHotspotIndex > this->customHelpTextLength) { + this->activeHelpHotspotIndex = this->customHelpTextLength; + } + int leftPosition; + int lineY = -1; + do { + leftPosition = this->lineLayoutTable[++lineY].leftBorder; + } while (leftPosition == -1); + while (true) { + iVar5 = textMemIndex; + BGR24 charColor = color; + local_12c = 1; + if (0 <= currentLinkId) { + charColor = linkColor; + } + local_114 = textMemIndex; + TextMemUnion textMemUnion; + textMemUnion.value + = MACRO_CALL_MEMBER(TextEditorState_Func::getWideCharOrWideCharPointer, this)(&textMemIndex); + if (this->useAlternateHelpTab && textMemUnion.value < L' ' && textMemUnion.helpToken != HTT_NEWPARAGRAPH + && iVar5 == this->activeHelpHotspotIndex) { + lineEndY = lineY + currentFontLineHeight; + lineStartY = lineY; + if (param_1 == 1) { + int xModify = 0; + if (local_120) { + xModify = this->lineLayoutTable[lineY].unknown2 / 2; + } + local_10c = local_114 - local_11c; + if (this->unknown_0x2396C < 0) { + this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; + } + this->unknown_0x2396C = 0; + } + local_134 = 0; + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + this->dialogContentX + xModify - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, + this->dialogContentX + xModify - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + this->dialogContentX + xModify + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, + this->dialogContentX + xModify + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; + } + } + + iVar17 = local_11c; + switch (textMemUnion.helpToken) { + case HTT_PIC: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"DAT_PointerToTemporaryTextMemory[textMemIndex], + this->graphicFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); + ++textMemIndex; + switch ((HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex]) { + case HTT_PIC_LEFT: + wcscat(wideTextBuffer, L"LEFT>"); + textMemIndex += 2; + break; + case HTT_PIC_RIGHT: + wcscat(wideTextBuffer, L"RIGHT>"); + textMemIndex += 2; + break; + case HTT_PIC_CENTRE: + wcscat(wideTextBuffer, L"CENTRE>"); + textMemIndex += 2; + break; + case HTT_PIC_HERE: + wcscat(wideTextBuffer, L"HERE>"); + textMemIndex += 2; + break; + default: + textMemIndex += 2; + break; + } + break; + } else { + ++imageCount; + if (param_1 == 1) { + if (this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] != 3) { + textMemIndex += 3; + continue; + } + } else { + if (param_1 + || (imageCount != this->imageHotspotCount + && this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] != 3)) { + textMemIndex += 3; + continue; + } + if (imageCount == this->imageHotspotCount) { + this->imageHotspotTable[this->imageHotspotCount].yPos = lineY + 25; + this->imageHotspotTable[this->imageHotspotCount].imageRelated + = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + this->imageHotspotTable[this->imageHotspotCount].unknown3 = currentLinkId; + } + } + HelpTextPicturePositionToken positionToken + = (HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1]; + int imageHeight = DAT_TextureRenderCoreObject::instance + .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] + .height; + int imageWidth = DAT_TextureRenderCoreObject::instance + .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] + .width; + switch (positionToken) { + case HTT_PIC_LEFT: + this->imageHotspotTable[this->imageHotspotCount].xPos = this->lineLayoutTable[lineY].leftBorder; + for (int i = 0; i < imageHeight + 50; ++i) { + this->lineLayoutTable[lineY + i].rightBorder + = this->lineLayoutTable[lineY].leftBorder + 25 + imageWidth; + } + break; + case HTT_PIC_RIGHT: + this->imageHotspotTable[this->imageHotspotCount].xPos + = this->lineLayoutTable[lineY].rightBorder - imageWidth; + for (int i = 0; i < imageHeight + 50; ++i) { + this->lineLayoutTable[lineY + i].rightBorder + = this->lineLayoutTable[lineY].rightBorder - imageWidth - 25; + this->lineLayoutTable[lineY + i].leftBorder = -1; + } + break; + case HTT_PIC_CENTRE: + this->imageHotspotTable[this->imageHotspotCount].xPos + = (this->dialogContentHeight - imageWidth) / 2; + for (int i = 0; i < imageHeight + 50; ++i) { + this->lineLayoutTable[lineY + i].leftBorder = -1; + } + break; + case HTT_PIC_HERE: + imageWidth += 3; + if (this->lineLayoutTable[lineY].rightBorder < imageWidth + leftPosition) { + local_f0 = FALSE; + if (local_120) { + this->lineLayoutTable[lineY].unknown2 + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + local_120 = centreActive; + } + do { + lineY += currentFontLineHeight + 1; + do { + leftPosition = this->lineLayoutTable[lineY++].leftBorder; + } while (leftPosition == -1); + } while (this->lineLayoutTable[lineY].rightBorder < leftPosition + imageWidth); + if (this->useAlternateHelpTab && param_1 == 1) { + ++local_134; + local_100 = local_11c; + local_11c = local_114; + if (0 < this->unknown_0x2396C && 1 < local_134) { + this->activeHelpHotspotIndex = iVar17 + local_10c; + local_134 = -10000; + if (local_114 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = local_114 + -1; + } + this->unknown_0x2396C = 0; + } + } + currentFontLineHeight = currentFontClass->lineHeight_0x14; + } + if (currentFontLineHeight < imageHeight) { + currentFontLineHeight = imageHeight; + } + leftPosition += imageWidth; + if (param_1 != 1 && imageCount == this->imageHotspotCount) { + this->imageHotspotTable[this->imageHotspotCount].xPos = leftPosition - imageWidth; + this->imageHotspotTable[this->imageHotspotCount].yPos = lineY; + ++this->imageHotspotCount; + } + break; + } + textMemIndex += 3; + if (positionToken == HTT_PIC_HERE || param_1) { + continue; + } + ++this->imageHotspotCount; + DAT_TextManagerObject::instance.field6_0x18 = 0; + return FALSE; + } + case HTT_FONT: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)( + wideTextBuffer, L"", this->DAT_PointerToTemporaryTextMemory[textMemIndex]); + textMemIndex += 2; + break; + } else { + int fontSize = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + if (fontSize < 15) { + fontSize += 5; + } + textMemIndex = textMemIndex + 2; + currentFontClass = DAT_TextManagerObject::instance.fontSizeClassArray + fontSize; + dVar14 = DAT_TextManagerObject::instance.fontSizeClassArray[fontSize].lineHeight_0x14; + if (currentFontLineHeight < dVar14 || !local_f0) { + currentFontLineHeight = dVar14; + } + continue; + } + case HTT_COLOUR: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + DAT_UserHelpDefinedData::instance + .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] + .name_0x0); + textMemIndex += 2; + break; + } else { + if (param_1 == 1) { + int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + + uint colorRed; + uint colorGreen; + uint colorBlue; + if (this->helpDialogVariant == 2 && colorIndex == 1) { + colorRed = 0xd7; + colorGreen = 0xd2; + colorBlue = 0xa4; + } else { + colorRed = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4; + colorGreen = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8; + colorBlue = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc; + } + textMemIndex += 2; + color = ((colorBlue << 16) & 0xff0000) | ((colorGreen << 8) & 0x00ff00) | colorRed & 0x0000ff; + } else { + textMemIndex += 2; + } + continue; + } + case HTT_LINKCOLOUR: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + DAT_UserHelpDefinedData::instance + .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] + .name_0x0); + textMemIndex += 2; + break; + } else { + if (param_1 == 1) { + int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + textMemIndex += 2; + linkColor + = ((DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc << 16) & 0xff0000) + | ((DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8 << 8) & 0x00ff00) + | DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4 & 0x0000ff; + } else { + textMemIndex += 2; + } + continue; + } + case HTT_LINK: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + DAT_UserHelpDefinedData::instance + .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); + textMemIndex += 2; + break; + } else { + currentLinkId = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + if (param_1 == 1) { + DAT_TextManagerObject::instance.field6_0x18 = 1; + } + textMemIndex += 2; + continue; + } + case HTT_INCLUDE: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + DAT_UserHelpDefinedData::instance + .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); + textMemIndex += 2; + break; + } else { + textMemIndex += 2; + continue; + } + case HTT_SOUND: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + this->soundFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); + textMemIndex += 2; + break; + } else { + if (param_1 == 1 && -1 < lineY - this->helpContentScrollOffsetY + && lineY - this->helpContentScrollOffsetY < this->dialogContentWidth + && !this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]) { + this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] = 1; + } + textMemIndex += 2; + continue; + } + case HTT_ENDLINK: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + wcscpy(wideTextBuffer, L"<\\LINK>"); + break; + } else { + currentLinkId = -1; + if (param_1 == 1) { + DAT_TextManagerObject::instance.field6_0x18 = 0; + } + continue; + } + case (wchar_t*)13: // unknown case? + default: + pwVar6 = textMemUnion.text; + goto switchD_00460064_caseD_d; + case HTT_STRING: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + MACRO_CALL(Global_Func::PrintToDestination)( + wideTextBuffer, L"", this->DAT_PointerToTemporaryTextMemory[textMemIndex]); + textMemIndex += 2; + break; + } else { + textMemIndex += 2; + continue; + } + case HTT_CENTRE: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + wcscpy(wideTextBuffer, L""); + break; + } else { + centreActive = TRUE; + local_120 = TRUE; + continue; + } + case HTT_ENDCENTRE: + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + wcscpy(wideTextBuffer, L"<\\CENTRE>"); + break; + } else { + centreActive = FALSE; + continue; + } + case HTT_NEWPARAGRAPH: + if (local_120) { + this->lineLayoutTable[lineY].unknown2 = this->lineLayoutTable[lineY].rightBorder - leftPosition; + local_120 = centreActive; + } + if (this->useAlternateHelpTab && iVar5 == this->activeHelpHotspotIndex) { + lineEndY = currentFontLineHeight + lineY; + iVar12 = 0; + lineStartY = lineY; + if (param_1 == 1) { + if (local_120) { + iVar12 = this->lineLayoutTable[lineY].unknown2 / 2; + } + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + this->dialogContentX + iVar12 - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, + this->dialogContentX + iVar12 - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + this->dialogContentX + iVar12 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, + this->dialogContentX + iVar12 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; + } + } + lineY += 3 + currentFontLineHeight; + local_f0 = FALSE; + do { + leftPosition = this->lineLayoutTable[lineY++].leftBorder; + } while (leftPosition == -1); + currentFontLineHeight = currentFontClass->lineHeight_0x14; + iVar12 = local_11c; + if (this->useAlternateHelpTab != 0) { + local_100 = local_11c; + if (param_1 == 1) { + ++local_134; + if (0 < this->unknown_0x2396C && 1 < local_134) { + this->activeHelpHotspotIndex = local_10c + local_11c; + local_134 = -10000; + if (iVar5 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = iVar5 + -1; + } + this->unknown_0x2396C = 0; + } + } + iVar12 = iVar5; + if (iVar5 == this->activeHelpHotspotIndex && param_1 == 1) { + local_10c = 0; + if (this->unknown_0x2396C < 0) { + this->activeHelpHotspotIndex = DAT_00df3348::instance + local_11c; + if (iVar5 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = iVar5 + -1; + } + this->unknown_0x2396C = 0; + } + local_134 = 0; + } + } + local_11c = iVar12; + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + wcscpy(wideTextBuffer, L""); + break; + } + continue; + case HTT_TAB: // TODO?: unknown token + if (this->helpDialogSubMode == 1) { + charColor = 0xff; + local_12c = 0; + wcscpy(wideTextBuffer, L""); + break; + } else { + if (this->lineLayoutTable[lineY].rightBorder < leftPosition + 30) { + local_f0 = FALSE; + if (local_120) { + this->lineLayoutTable[lineY].unknown2 + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + local_120 = centreActive; + } + do { + lineY += currentFontLineHeight + 1; + do { + leftPosition = this->lineLayoutTable[lineY++].leftBorder; + } while (leftPosition == -1); + } while (this->lineLayoutTable[lineY].rightBorder < leftPosition + 30); + iVar12 = local_11c; + if (this->useAlternateHelpTab && param_1 == 1) { + ++local_134; + local_100 = local_11c; + iVar12 = iVar5; + if (0 < this->unknown_0x2396C && 1 < local_134) { + this->activeHelpHotspotIndex = local_11c + local_10c; + local_134 = -10000; + if (iVar5 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = iVar5 + -1; + } + this->unknown_0x2396C = 0; + } + } + local_11c = iVar12; + currentFontLineHeight = currentFontClass->lineHeight_0x14; + } + leftPosition += 30; + continue; + } + case (wchar_t*)0: // TODO?: unknown token, or just NULL, meaning end? + if (param_1 == 0) { + this->topVisibleLineIndex = lineY + currentFontLineHeight - 1; + do { + ++this->topVisibleLineIndex; + if (this->lineLayoutTable[this->topVisibleLineIndex].leftBorder == 25 + && this->lineLayoutTable[this->topVisibleLineIndex].rightBorder + == this->dialogContentHeight - 25) { + break; + } + } while (this->topVisibleLineIndex < 20000); + this->topVisibleLineIndex += 5; + if (this->useAlternateHelpTab) { + if (lineStartY < this->helpContentScrollOffsetY) { + this->helpContentScrollOffsetY = lineStartY; + } + if (lineEndY > this->helpContentScrollOffsetY + this->dialogContentWidth) { + this->helpContentScrollOffsetY = (lineEndY - this->dialogContentWidth) + 5; + DAT_TextManagerObject::instance.field6_0x18 = 0; + return TRUE; + } + } + DAT_TextManagerObject::instance.field6_0x18 = 0; + return TRUE; + } + if (!this->useAlternateHelpTab) { + DAT_TextManagerObject::instance.field6_0x18 = 0; + return TRUE; + } + DAT_00df3348::instance = local_10c; + if (0 < this->unknown_0x2396C && local_134 == 1) { + this->activeHelpHotspotIndex = local_10c + local_11c; + if (this->activeHelpHotspotIndex > this->customHelpTextLength) { + this->activeHelpHotspotIndex = this->customHelpTextLength; + } + this->unknown_0x2396C = 0; + } + if (!local_e4 && this->activeHelpHotspotIndex && DAT_00df334c::instance) { + --this->activeHelpHotspotIndex; + this->unknown_0x23970 = 0; + DAT_TextManagerObject::instance.field6_0x18 = 0; + return TRUE; + } + DAT_00df334c::instance = 0; + DAT_TextManagerObject::instance.field6_0x18 = 0; + return TRUE; + } + // NOTE: This is either the local text buffer, or the text directly from the text memory... + pwVar6 = wideTextBuffer; + switchD_00460064_caseD_d: + if (0x1f < (int)pwVar6) { + iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWidthOfWideText, currentFontClass)( + pwVar6, wcslen((wchar_t*)pwVar6)); + iVar5 = local_11c; + local_f4 = leftPosition + iVar12; + if (this->lineLayoutTable[lineY].rightBorder < local_f4) { + local_f0 = FALSE; + if (local_120) { + this->lineLayoutTable[lineY].unknown2 = this->lineLayoutTable[lineY].rightBorder - leftPosition; + local_120 = centreActive; + } + lineY += 1 + currentFontLineHeight; + do { + leftPosition = this->lineLayoutTable[lineY++].leftBorder; + } while (leftPosition == -1); + currentFontLineHeight = currentFontClass->lineHeight_0x14; + if (this->useAlternateHelpTab) { + ++local_134; + local_100 = local_11c; + local_11c = local_114; + if (0 < this->unknown_0x2396C && 1 < local_134) { + this->activeHelpHotspotIndex = iVar5 + local_10c; + local_134 = -10000; + if (local_114 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = local_114 - 1; + } + this->unknown_0x2396C = 0; + } + } + local_f4 = iVar12 + leftPosition; + if (this->lineLayoutTable[lineY].rightBorder < (int)local_f4) { + local_f8 = 0; + if (local_120) { + local_f8 = this->lineLayoutTable[lineY].unknown2 / 2; + } + int const wideStrLength = wcslen((wchar_t*)pwVar6); + for (local_118 = 0; local_118 < wideStrLength; ++local_118) { + int wideCharWidth = MACRO_CALL_MEMBER( + FontSizeClass_Func::getWideCharWidth, currentFontClass)(textMemUnion.text[local_118]); + while (this->lineLayoutTable[lineY].rightBorder < leftPosition + wideCharWidth) { + iVar5 = local_11c; + if (local_120) { + this->lineLayoutTable[lineY].unknown2 + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + local_120 = centreActive; + } + lineY += currentFontLineHeight + 1; + if (this->useAlternateHelpTab && param_1 == 1) { + ++local_134; + local_100 = local_11c; + local_11c = local_114 + local_118; + if (0 < this->unknown_0x2396C && 1 < local_134) { + this->activeHelpHotspotIndex = iVar5 + local_10c; + local_134 = -10000; + if (local_114 + local_118 <= this->activeHelpHotspotIndex) { + this->activeHelpHotspotIndex = local_114 + local_118 - 1; + } + this->unknown_0x2396C = 0; + } + } + do { + leftPosition = this->lineLayoutTable[lineY++].leftBorder; + } while (leftPosition == -1); + if (local_120) { + local_f8 = this->lineLayoutTable[lineY].unknown2 / 2; + } + } + if (!this->useAlternateHelpTab || local_114 + local_118 != this->activeHelpHotspotIndex) { + if (param_1 == 1) { + iVar5 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( + textMemUnion.text[local_118], this->dialogContentX + local_f8 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + lineY, charColor, 0); + local_f0 = TRUE; + if (MACRO_CALL_MEMBER( + Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + this->dialogContentX + local_f8 + leftPosition - this->helpContentScrollX, + this->dialogContentY - this->helpContentScrollOffsetY + lineY + - this->helpContentScrollY, + iVar5 - this->dialogContentX + local_f8 + leftPosition, + currentFontLineHeight + 2)) { + if (local_12c) { + this->unknown_0x23964 = local_114 + local_118; + this->unknown_0x23968 = currentLinkId; + } else { + this->unknown_0x23964 = local_114; + } + } + } + } else { + lineEndY = lineY + currentFontLineHeight; + lineStartY = lineY; + if (param_1 == 1) { + if (local_12c) { + local_10c = (local_118 - local_11c) + local_114; + if (this->unknown_0x2396C < 0) { + this->activeHelpHotspotIndex = DAT_00df3348::instance + local_100; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; + } + this->unknown_0x2396C = 0; + } + local_134 = 0; + MACRO_CALL_MEMBER( + UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + this->dialogContentX + local_f8 - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + -1 + lineY, + this->dialogContentX + local_f8 - 1 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, + DAT_PencilRenderCore::ptr)(this->dialogContentX + local_f8 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, + this->dialogContentX + local_f8 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; + } + iVar5 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( + textMemUnion.text[local_118], this->dialogContentX + local_f8 + leftPosition, + this->dialogContentY - this->helpContentScrollOffsetY + lineY, charColor, 0); + local_f0 = TRUE; + if (MACRO_CALL_MEMBER( + Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + this->dialogContentX + local_f8 + leftPosition - this->helpContentScrollX, + this->dialogContentY - this->helpContentScrollOffsetY + lineY + - this->helpContentScrollY, + iVar5 - this->dialogContentX + local_f8 + leftPosition, + currentFontLineHeight + 2)) { + if (local_12c) { + this->unknown_0x23964 = local_114 + local_118; + this->unknown_0x23968 = currentLinkId; + } else { + this->unknown_0x23964 = local_114; + } + } + } + } + leftPosition += wideCharWidth; + } + continue; + } + } + iVar5 = this->dialogContentX + leftPosition; + local_104 = (this->dialogContentY - this->helpContentScrollOffsetY) + lineY; + if (local_120) { + iVar5 += this->lineLayoutTable[lineY].unknown2 / 2; + } + int const wideStrLength = wcslen((wchar_t*)pwVar6); + for (int i = 0; i < wideStrLength; ++i) { + local_f8 = local_114 - local_11c; + if ((this->useAlternateHelpTab == 0) || (i + local_114 != this->activeHelpHotspotIndex)) { + if (param_1 == 1) { + local_f0 = TRUE; + iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( + textMemUnion.text[i], iVar5, local_104, charColor, 0); + if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, + iVar12 - iVar5, currentFontLineHeight + 2)) { + if (local_12c) { + this->unknown_0x23964 = i + local_114; + this->unknown_0x23968 = currentLinkId; + } else { + this->unknown_0x23964 = local_114; + } + } + } else { + dVar14 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( + textMemUnion.text[i]); + iVar12 = iVar5 + dVar14; + } + } else { + if (param_1 == 1 && local_12c) { + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, + DAT_PencilRenderCore::ptr)(iVar5 + -1, local_104 - 1, iVar5 + -1, + local_104 + 1 + currentFontLineHeight, COL_DARK_LIME::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, + DAT_PencilRenderCore::ptr)(iVar5, local_104 - 1, iVar5, + local_104 + 1 + currentFontLineHeight, COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; + } + lineEndY = lineY + currentFontLineHeight; + lineStartY = lineY; + if (param_1 == 1) { + local_10c = local_f8 + i; + local_134 = 0; + if (this->unknown_0x2396C < 0 && local_12c) { + this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c + -1; + } + this->unknown_0x2396C = 0; + } + local_f0 = TRUE; + iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( + textMemUnion.text[i], iVar5, local_104, charColor, 0); + if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, + iVar12 - iVar5, currentFontLineHeight + 2)) { + if (local_12c) { + this->unknown_0x23964 = i + local_114; + this->unknown_0x23968 = currentLinkId; + } else { + this->unknown_0x23964 = local_114; + } + } + } else { + dVar14 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( + textMemUnion.text[i]); + iVar12 = iVar5 + dVar14; + } + } + iVar5 = iVar12; + } + leftPosition = local_f4; + } + } + } + +} +} From a21f1db29ab3cef1f205626716ab35fa8cab0d05 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Mon, 21 Sep 2026 23:08:06 +0200 Subject: [PATCH 42/44] reimplement: OpenSHC::Text::TextEditorState adapt to upstream changes --- src/OpenSHC/OS/OS.cpp | 2 +- src/OpenSHC/Text/TextEditorState.hpp | 11 +- .../Constructor_TextEditorState.cpp | 6 +- .../bltTextToScreenIfNeedBe.cpp | 4 +- .../TextEditorState/drawBorderStyle0x20.cpp | 6 +- .../drawHelpWindowBackground.cpp | 4 +- .../Text/TextEditorState/helpToken.cpp | 16 +- .../initializeAndLayoutHelpText.cpp | 2 +- .../openBuildingHelpDialog.cpp | 4 +- .../openCreditsScrollDialog.cpp | 4 +- .../TextEditorState/openInGameHelpDialog.cpp | 4 +- .../openMapDescriptionEditorDialog.cpp | 4 +- .../openScenarioHelpDialog.cpp | 4 +- .../openUnusedHelpTextEditorDialog.cpp | 10 +- src/OpenSHC/Text/TextEditorState/parseHlp.cpp | 101 +++++----- .../processHelpRichTextTokens.cpp | 174 +++++++++--------- .../TextEditorState/readCrusaderHelpHlp.cpp | 5 +- .../renderHelpImageHotspots.cpp | 10 +- .../saveHelpFileToResource.cpp | 84 ++++----- .../TextEditorState/setHelpWindowBounds.cpp | 4 +- .../TextEditorState/setTextRenderingLogic.cpp | 8 +- 21 files changed, 232 insertions(+), 235 deletions(-) diff --git a/src/OpenSHC/OS/OS.cpp b/src/OpenSHC/OS/OS.cpp index e300ed41a5..686831bf59 100644 --- a/src/OpenSHC/OS/OS.cpp +++ b/src/OpenSHC/OS/OS.cpp @@ -85,7 +85,7 @@ namespace OS { wchar_t* _wcsncpy(wchar_t* _Dest, wchar_t* _Source, size_t _Count) { return wcsncpy(_Dest, _Source, _Count); } // STUB: STRONGHOLDCRUSADER 0x00580B69 - int __wcsicmp(wchar_t* _Str1, wchar_t* _Str2) { return _wcsicmp(_Str1, _Str2); } + int __wcsicmp(wchar_t const* _Str1, wchar_t const* _Str2) { return _wcsicmp(_Str1, _Str2); } // Only jumps to _free in game version // STUB: STRONGHOLDCRUSADER 0x00580DC1 diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index be0f30e8e0..7135598688 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -20,16 +20,9 @@ namespace OpenSHC { namespace Text { - struct ImageHotspot { - short xPos; - short yPos; - short imageRelated; - short unknown3; - }; - struct LineLayout { - short unknown0; - short unknown1; + short leftBorder; + short rightBorder; short unknown2; }; diff --git a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp index afb18c1b73..e98ffe2c0d 100644 --- a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp +++ b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp @@ -8,11 +8,11 @@ namespace OpenSHC { namespace Text { // FUNCTION: STRONGHOLDCRUSADER 0x0045F130 - TextEditorState* TextEditorState ::Constructor_TextEditorState() + TextEditorState* TextEditorState::Constructor_TextEditorState() { this->isDialogStateInitialized = 0; this->helpDialogVariant = 0; - this->unknown_0x23960 = 0; + this->field48_0x23960 = 0; this->helpDialogSubMode = 0; this->useAlternateHelpTab = 0; this->customHelpTextLength = 0; @@ -21,7 +21,7 @@ namespace Text { MACRO_CALL_MEMBER(TextEditorState_Func::resetHelpStateFields, this)(); - this->DAT_PointerToTemporaryTextMemory = MACRO_CALL(OS_Func::_malloc)(40000); + this->DAT_PointerToTemporaryTextMemory = (LPWSTR)MACRO_CALL(OS_Func::_malloc)(40000); this->customTextMaxLength = -1; // FIXME:: Requires a finishing zero case, or it will not set the counter diff --git a/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp b/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp index d6bb78b88b..8e81abad4a 100644 --- a/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp +++ b/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp @@ -11,7 +11,7 @@ namespace Text { // FUNCTION: STRONGHOLDCRUSADER 0x0045D690 void TextEditorState::bltTextToScreenIfNeedBe() { - if (!DAT_TextEditorState::instance.unknown_0x23960) { + if (!DAT_TextEditorState::instance.field48_0x23960) { return; } if (this->savedMenuViewType == UI::Enums::MVT_MAP_EDITOR_LANDSCAPING @@ -20,7 +20,7 @@ namespace Text { MACRO_CALL_MEMBER(UI::Rendering::WindowAndDirectDraw_Func::bltMapGameSurfaceToScreenMenuSurfaceComplete, DAT_WindowAndDirectDraw::ptr)(); } - DAT_TextEditorState::instance.unknown_0x23960 = FALSE; + DAT_TextEditorState::instance.field48_0x23960 = FALSE; } } diff --git a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp index c36e3e66ae..bb01a0ba2e 100644 --- a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp +++ b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp @@ -22,12 +22,12 @@ namespace Text { // FIXME: ContentHeight and ContentWidth or the dialogWidth and dialogHeight are swapped int const contentX = this->dialogX + DAT_00df2964::instance; int const contentY = this->dialogY + DAT_00df296c::instance; - int const contentWidth = this->dialogHeight - INT_00df2970::instance; - int const contentHeight = this->dialogWidth - INT_00df2968::instance; + int const contentHeight = this->dialogHeight - INT_00df2970::instance; + int const contentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = contentX; this->dialogContentY = contentY; - this->dialogContentHeight = contentHeight; this->dialogContentWidth = contentWidth; + this->dialogContentHeight = contentHeight; this->helpContentScrollX = DAT_ViewportRenderState::instance.viewportState.currentCameraOffsetX; this->helpContentScrollY = DAT_ViewportRenderState::instance.viewportState.currentCameraOffsetY; diff --git a/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp b/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp index ac5555d629..82378f4ff6 100644 --- a/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp +++ b/src/OpenSHC/Text/TextEditorState/drawHelpWindowBackground.cpp @@ -34,8 +34,8 @@ namespace Text { this->dialogX, this->dialogY, this->dialogWidth + this->dialogX, this->dialogHeight + this->dialogY, COL_VERY_DARK_GREY::instance.shortValue); MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( - this->dialogContentX, this->dialogContentY, this->dialogContentHeight + this->dialogContentX, - this->dialogContentWidth + this->dialogContentY, COL_BLACK::instance.shortValue); + this->dialogContentX, this->dialogContentY, this->dialogContentWidth + this->dialogContentX, + this->dialogContentHeight + this->dialogContentY, COL_BLACK::instance.shortValue); MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawColorBox, DAT_PencilRenderCore::ptr)( this->dialogX, this->dialogY + this->dialogHeight, this->dialogWidth + this->dialogX, this->dialogY + this->dialogHeight + 60, COL_DARK_CYAN_GREY::instance.shortValue); diff --git a/src/OpenSHC/Text/TextEditorState/helpToken.cpp b/src/OpenSHC/Text/TextEditorState/helpToken.cpp index 6931a374e6..8cfb867ffb 100644 --- a/src/OpenSHC/Text/TextEditorState/helpToken.cpp +++ b/src/OpenSHC/Text/TextEditorState/helpToken.cpp @@ -7,16 +7,16 @@ namespace Text { int TextEditorState::helpToken_getHelpTokenAdvanceLength(HelpTextToken token) { switch (token) { - case HTT_PIC: + case Enums::HTT_PIC: return 4; - case HTT_FONT: - case HTT_COLOUR: - case HTT_LINK: - case HTT_LINKCOLOUR: - case HTT_SOUND: - case HTT_STRING: - case HTT_INCLUDE: + case Enums::HTT_FONT: + case Enums::HTT_COLOUR: + case Enums::HTT_LINK: + case Enums::HTT_LINKCOLOUR: + case Enums::HTT_SOUND: + case Enums::HTT_STRING: + case Enums::HTT_INCLUDE: return 3; default: diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp index 99fef53e0f..ac6882fef2 100644 --- a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp +++ b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp @@ -8,7 +8,7 @@ namespace Text { { for (int i = 0; i < 20000; ++i) { this->lineLayoutTable[i].leftBorder = 25; - this->lineLayoutTable[i].rightBorder = this->dialogContentHeight - 25; + this->lineLayoutTable[i].rightBorder = this->dialogContentWidth - 25; this->lineLayoutTable[i].unknown2 = 0; } // Adds vertical space at start diff --git a/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp index fd849ca465..5c40b0e56a 100644 --- a/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp @@ -62,8 +62,8 @@ namespace Text { int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = dialogContentX; this->dialogContentY = dialogContentY; - this->dialogContentHeight = dialogContentWidth; - this->dialogContentWidth = dialogContentHeight; + this->dialogContentWidth = dialogContentWidth; + this->dialogContentHeight = dialogContentHeight; for (int i = 28; i >= 0; --i) { this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; diff --git a/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp b/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp index cc8d182e5f..f7b398baef 100644 --- a/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp @@ -56,8 +56,8 @@ namespace Text { int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = dialogContentX; this->dialogContentY = dialogContentY; - this->dialogContentHeight = dialogContentWidth; - this->dialogContentWidth = dialogContentHeight; + this->dialogContentWidth = dialogContentWidth; + this->dialogContentHeight = dialogContentHeight; for (int i = 28; i >= 0; --i) { this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; diff --git a/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp index cdb41b1d71..f8c1c455b0 100644 --- a/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp @@ -57,8 +57,8 @@ namespace Text { int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = dialogContentX; this->dialogContentY = dialogContentY; - this->dialogContentHeight = dialogContentWidth; - this->dialogContentWidth = dialogContentHeight; + this->dialogContentWidth = dialogContentWidth; + this->dialogContentHeight = dialogContentHeight; for (int i = 28; i >= 0; --i) { this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; diff --git a/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp b/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp index ab6933b088..d024a872a7 100644 --- a/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp @@ -58,8 +58,8 @@ namespace Text { int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = dialogContentX; this->dialogContentY = dialogContentY; - this->dialogContentHeight = dialogContentWidth; - this->dialogContentWidth = dialogContentHeight; + this->dialogContentWidth = dialogContentWidth; + this->dialogContentHeight = dialogContentHeight; for (int i = 28; i >= 0; --i) { this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; diff --git a/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp index cbe2b44f4b..8ce0c7f67d 100644 --- a/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp @@ -57,8 +57,8 @@ namespace Text { int const dialogContentWidth = this->dialogWidth - INT_00df2968::instance; this->dialogContentX = dialogContentX; this->dialogContentY = dialogContentY; - this->dialogContentHeight = dialogContentWidth; - this->dialogContentWidth = dialogContentHeight; + this->dialogContentWidth = dialogContentWidth; + this->dialogContentHeight = dialogContentHeight; for (int i = 28; i >= 0; --i) { this->helpSectionHistoryStack[i + 1] = this->helpSectionHistoryStack[i]; diff --git a/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp b/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp index 45951bd8d2..9ffdd0038c 100644 --- a/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp +++ b/src/OpenSHC/Text/TextEditorState/openUnusedHelpTextEditorDialog.cpp @@ -30,7 +30,7 @@ namespace Text { this->savedMenuViewType = DAT_GameCore::instance.currentMenuViewType; this->savedActiveMenuTab = DAT_GameCore::instance.activeMenuTab.tabType; this->savedMenuFlag = DAT_GameCore::instance.unknownAlwaysZero01; - this->unknown_0x23960 = 1; + this->field48_0x23960 = 1; this->isDialogStateInitialized = TRUE; this->useInGameHelpHandler = FALSE; this->helpDialogVariant = 0; @@ -72,13 +72,13 @@ namespace Text { if (!this->useWideHelpLayout) { this->dialogContentX = this->dialogX + 10; this->dialogContentY = this->dialogY + 10; - this->dialogContentHeight = 600; - this->dialogContentWidth = 435; + this->dialogContentWidth = 600; + this->dialogContentHeight = 435; } else { this->dialogContentX = this->dialogX + 10; this->dialogContentY = this->dialogY + 10; - this->dialogContentHeight = 664; - this->dialogContentWidth = 291; + this->dialogContentWidth = 664; + this->dialogContentHeight = 291; } for (int i = 28; i >= 0; --i) { diff --git a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp index 792efc7001..cfc8eb8fb3 100644 --- a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp +++ b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp @@ -4,6 +4,9 @@ #include "OpenSHC/OS.func.hpp" #include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" #include "OpenSHC/Util/WideCharMultiByteState.func.hpp" +#include "OpenSHC/Text/Enums/HelpTextPicturePositionToken.hpp" +#include "OpenSHC/wstring-literals.hpp" +#include "OpenSHC/string-literals.hpp" #include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" #include "OpenSHC/Globals/DAT_TextEditorState.hpp" @@ -14,8 +17,6 @@ namespace OpenSHC { namespace Text { - // TODO: fix L-strings - // FUNCTION: STRONGHOLDCRUSADER 0x0045F5B0 void TextEditorState::parseHlp() { @@ -52,23 +53,23 @@ namespace Text { wchar_t* hlpTag = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(filePointer[_filePointerIndex]); if (hlpTag) { - if (!MACRO_CALL(OS_Func::__wcsicmp)(L"header", hlpTag)) { + if (!MACRO_CALL(OS_Func::__wcsicmp)(u_header_005a5774, hlpTag)) { headerActive = TRUE; continue; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\header", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u__header_005a5764, hlpTag)) { headerActive = FALSE; continue; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"body", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_body_005a5758, hlpTag)) { bodyActive = TRUE; continue; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\body", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u__body_005a574c, hlpTag)) { bodyActive = FALSE; continue; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"loadpic", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_loadpic_005a573c, hlpTag)) { if (headerActive) { wchar_t* resourceName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); @@ -83,7 +84,7 @@ namespace Text { DAT_TextureRenderCoreObject::ptr)(resourceNameChars)) { validPic = false; } else if (!MACRO_CALL(OS_Func::__stricmp)( - resourceNameChars, "st99_dog_cage.tgx")) { + resourceNameChars, s_st99_dog_cage_tgx_005a5728)) { validPic = false; } if (!validPic) { @@ -97,7 +98,7 @@ namespace Text { } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"pic", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_pic_005a5720, hlpTag)) { if (bodyActive) { wchar_t* picId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); @@ -105,7 +106,7 @@ namespace Text { if (MACRO_CALL(OS_Func::__wtol)(picId) < loadedGraphics[_filePointerIndex]) { if (graphicIndexes[_filePointerIndex][MACRO_CALL(OS_Func::__wtol)(picId)] != -1) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_PIC; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_PIC; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = graphicIndexes[_filePointerIndex][MACRO_CALL(OS_Func::__wtol)(picId)]; wchar_t* picPosition = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, @@ -113,21 +114,21 @@ namespace Text { if (!picPosition) { closeFile = TRUE; } else { - if (!MACRO_CALL(OS_Func::__wcsicmp)(L"left", picPosition)) { + if (!MACRO_CALL(OS_Func::__wcsicmp)(u_left_005a5714, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] - = HTT_PIC_LEFT; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"right", picPosition)) { + = Enums::HTPPT_LEFT; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_right_005a5708, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] - = HTT_PIC_RIGHT; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"centre", picPosition)) { + = Enums::HTPPT_RIGHT; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_centre_005a56f8, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] - = HTT_PIC_CENTRE; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"here", picPosition)) { + = Enums::HTPPT_CENTRE; + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_here_005a56ec, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] - = HTT_PIC_HERE; + = Enums::HTPPT_HERE; } } - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_PIC; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_PIC; continue; } } @@ -139,46 +140,46 @@ namespace Text { } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"font", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_font_005a56e0, hlpTag)) { if (bodyActive) { wchar_t* fontId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); if (fontId) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_FONT; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_FONT; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = (short)MACRO_CALL(OS_Func::__wtol)(fontId); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_FONT; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_FONT; continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"colour", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_colour_005a56d0, hlpTag)) { if (bodyActive) { wchar_t* colorId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); if (colorId) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_COLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_COLOUR; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = (short)MACRO_CALL(OS_Func::__wtol)(colorId); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_COLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_COLOUR; continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"linkcolour", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_linkcolour_005a56b8, hlpTag)) { if (bodyActive) { wchar_t* linkColorId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); if (linkColorId) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINKCOLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_LINKCOLOUR; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = (short)MACRO_CALL(OS_Func::__wtol)(linkColorId); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINKCOLOUR; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_LINKCOLOUR; continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"link", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_link_005a56ac, hlpTag)) { if (bodyActive) { wchar_t* linkName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); @@ -188,38 +189,38 @@ namespace Text { DAT_WideCharMultiByteState::ptr)(linkNameChars, linkName); int const helpSectionIndex = MACRO_CALL_MEMBER( TextEditorState_Func::findOrAddHelpSectionName, this)(linkNameChars); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINK; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_LINK; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = helpSectionIndex; - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_LINK; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_LINK; continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\link", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u__link_005a56a0, hlpTag)) { if (bodyActive) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_ENDLINK; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_ENDLINK; continue; } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"newparagraph", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_newparagraph_005a5684, hlpTag)) { if (bodyActive) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_NEWPARAGRAPH; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_NEWPARAGRAPH; continue; } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"centre", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_centre_005a56f8, hlpTag)) { if (bodyActive) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_CENTRE; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_CENTRE; continue; } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\centre", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u__centre_005a5674, hlpTag)) { if (bodyActive) { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_ENDCENTRE; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_ENDCENTRE; continue; } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"sound", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_sound_005a5668, hlpTag)) { if (bodyActive) { wchar_t* soundName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); @@ -229,14 +230,14 @@ namespace Text { DAT_WideCharMultiByteState::ptr)(soundNameChars, soundName); int const soundIndex = MACRO_CALL_MEMBER( TextEditorState_Func::findOrAddSoundName, this)(soundNameChars); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_SOUND; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_SOUND; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = soundIndex; - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_SOUND; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_SOUND; continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"include", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_include_005a5658, hlpTag)) { if (bodyActive) { if (DAT_TextEditorState::instance.useAlternateHelpTab) { wchar_t* includeName = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( @@ -248,9 +249,9 @@ namespace Text { DAT_WideCharMultiByteState::ptr)(includeNameChars, includeName); int const helpSectionIndex = MACRO_CALL_MEMBER( TextEditorState_Func::findOrAddHelpSectionName, this)(includeNameChars); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_INCLUDE; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_INCLUDE; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = helpSectionIndex; - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_INCLUDE; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_INCLUDE; continue; } } else { @@ -275,7 +276,7 @@ namespace Text { } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"string", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_string_005a5648, hlpTag)) { if (bodyActive) { wchar_t* stringId = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)( filePointer[_filePointerIndex]); @@ -290,7 +291,7 @@ namespace Text { wchar_t const ch = this->intArray1[textIndex][i++]; if (ch == L'\n') { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] - = HTT_NEWPARAGRAPH; + = Enums::HTT_NEWPARAGRAPH; } else if (ch >= L' ') { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = ch; } @@ -298,15 +299,15 @@ namespace Text { } } else { - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_STRING; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_STRING; this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = (short)MACRO_CALL(OS_Func::__wtol)(stringId); - this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = HTT_STRING; + this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTT_STRING; } continue; } } - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(L"\\section", hlpTag)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u__section_005a5634, hlpTag)) { closeFile = TRUE; continue; } else { diff --git a/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp index 837af17dd5..760bec549c 100644 --- a/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp +++ b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp @@ -7,6 +7,8 @@ #include "OpenSHC/Input/MouseState.func.hpp" #include "OpenSHC/Text/FontSizeClass.func.hpp" #include "OpenSHC/UI/Rendering/PencilRenderCore.func.hpp" +#include "OpenSHC/Text/Enums/HelpTextPicturePositionToken.hpp" +#include "OpenSHC/wstring-literals.hpp" #include "OpenSHC/Globals/COL_DARK_LIME.hpp" #include "OpenSHC/Globals/DAT_00df3348.hpp" @@ -24,7 +26,7 @@ namespace Text { int value; wchar_t* text; HelpTextToken helpToken; - HelpTextPicturePositionToken picturePositionToken; + Enums::HelpTextPicturePositionToken picturePositionToken; }; // FUNCTION: STRONGHOLDCRUSADER 0x0045FDC0 @@ -65,9 +67,9 @@ namespace Text { if (!this->isTextHelpDialogMode) { return 1; } - this->unknown_0x23964 = -1; - this->unknown_0x23968 = -1; - if (this->unknown_0x2396C) { + this->field49_0x23964 = -1; + this->field50_0x23968 = -1; + if (this->field51_0x2396c) { DAT_00df334c::instance = 1; } if (this->activeHelpHotspotIndex < 0) { @@ -92,8 +94,8 @@ namespace Text { TextMemUnion textMemUnion; textMemUnion.value = MACRO_CALL_MEMBER(TextEditorState_Func::getWideCharOrWideCharPointer, this)(&textMemIndex); - if (this->useAlternateHelpTab && textMemUnion.value < L' ' && textMemUnion.helpToken != HTT_NEWPARAGRAPH - && iVar5 == this->activeHelpHotspotIndex) { + if (this->useAlternateHelpTab && textMemUnion.value < L' ' + && textMemUnion.helpToken != Enums::HTT_NEWPARAGRAPH && iVar5 == this->activeHelpHotspotIndex) { lineEndY = lineY + currentFontLineHeight; lineStartY = lineY; if (param_1 == 1) { @@ -102,12 +104,12 @@ namespace Text { xModify = this->lineLayoutTable[lineY].unknown2 / 2; } local_10c = local_114 - local_11c; - if (this->unknown_0x2396C < 0) { + if (this->field51_0x2396c < 0) { this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; if (this->activeHelpHotspotIndex >= local_11c) { this->activeHelpHotspotIndex = local_11c - 1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } local_134 = 0; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( @@ -128,29 +130,29 @@ namespace Text { iVar17 = local_11c; switch (textMemUnion.helpToken) { - case HTT_PIC: + case Enums::HTT_PIC: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"DAT_PointerToTemporaryTextMemory[textMemIndex], this->graphicFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); ++textMemIndex; - switch ((HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex]) { - case HTT_PIC_LEFT: - wcscat(wideTextBuffer, L"LEFT>"); + switch ((Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex]) { + case Enums::HTPPT_LEFT: + wcscat(wideTextBuffer, u_LEFT__005a5494); textMemIndex += 2; break; - case HTT_PIC_RIGHT: - wcscat(wideTextBuffer, L"RIGHT>"); + case Enums::HTPPT_RIGHT: + wcscat(wideTextBuffer, u_RIGHT__005a5484); textMemIndex += 2; break; - case HTT_PIC_CENTRE: - wcscat(wideTextBuffer, L"CENTRE>"); + case Enums::HTPPT_CENTRE: + wcscat(wideTextBuffer, u_CENTRE__005a5474); textMemIndex += 2; break; - case HTT_PIC_HERE: - wcscat(wideTextBuffer, L"HERE>"); + case Enums::HTPPT_HERE: + wcscat(wideTextBuffer, u_HERE__005a5468); textMemIndex += 2; break; default: @@ -179,8 +181,8 @@ namespace Text { this->imageHotspotTable[this->imageHotspotCount].unknown3 = currentLinkId; } } - HelpTextPicturePositionToken positionToken - = (HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1]; + Enums::HelpTextPicturePositionToken positionToken + = (Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1]; int imageHeight = DAT_TextureRenderCoreObject::instance .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .height; @@ -188,14 +190,14 @@ namespace Text { .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .width; switch (positionToken) { - case HTT_PIC_LEFT: + case Enums::HTPPT_LEFT: this->imageHotspotTable[this->imageHotspotCount].xPos = this->lineLayoutTable[lineY].leftBorder; for (int i = 0; i < imageHeight + 50; ++i) { this->lineLayoutTable[lineY + i].rightBorder = this->lineLayoutTable[lineY].leftBorder + 25 + imageWidth; } break; - case HTT_PIC_RIGHT: + case Enums::HTPPT_RIGHT: this->imageHotspotTable[this->imageHotspotCount].xPos = this->lineLayoutTable[lineY].rightBorder - imageWidth; for (int i = 0; i < imageHeight + 50; ++i) { @@ -204,14 +206,14 @@ namespace Text { this->lineLayoutTable[lineY + i].leftBorder = -1; } break; - case HTT_PIC_CENTRE: + case Enums::HTPPT_CENTRE: this->imageHotspotTable[this->imageHotspotCount].xPos - = (this->dialogContentHeight - imageWidth) / 2; + = (this->dialogContentWidth - imageWidth) / 2; for (int i = 0; i < imageHeight + 50; ++i) { this->lineLayoutTable[lineY + i].leftBorder = -1; } break; - case HTT_PIC_HERE: + case Enums::HTPPT_HERE: imageWidth += 3; if (this->lineLayoutTable[lineY].rightBorder < imageWidth + leftPosition) { local_f0 = FALSE; @@ -230,13 +232,13 @@ namespace Text { ++local_134; local_100 = local_11c; local_11c = local_114; - if (0 < this->unknown_0x2396C && 1 < local_134) { + if (0 < this->field51_0x2396c && 1 < local_134) { this->activeHelpHotspotIndex = iVar17 + local_10c; local_134 = -10000; if (local_114 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = local_114 + -1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } } currentFontLineHeight = currentFontClass->lineHeight_0x14; @@ -253,19 +255,19 @@ namespace Text { break; } textMemIndex += 3; - if (positionToken == HTT_PIC_HERE || param_1) { + if (positionToken == Enums::HTPPT_HERE || param_1) { continue; } ++this->imageHotspotCount; DAT_TextManagerObject::instance.field6_0x18 = 0; return FALSE; } - case HTT_FONT: + case Enums::HTT_FONT: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; MACRO_CALL(Global_Func::PrintToDestination)( - wideTextBuffer, L"", this->DAT_PointerToTemporaryTextMemory[textMemIndex]); + wideTextBuffer, u__FONT__d__005a5454, this->DAT_PointerToTemporaryTextMemory[textMemIndex]); textMemIndex += 2; break; } else { @@ -281,11 +283,11 @@ namespace Text { } continue; } - case HTT_COLOUR: + case Enums::HTT_COLOUR: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__COLOUR__S__005a5824, DAT_UserHelpDefinedData::instance .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .name_0x0); @@ -314,11 +316,11 @@ namespace Text { } continue; } - case HTT_LINKCOLOUR: + case Enums::HTT_LINKCOLOUR: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__LINKCOLOUR__S__005a5804, DAT_UserHelpDefinedData::instance .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .name_0x0); @@ -337,11 +339,11 @@ namespace Text { } continue; } - case HTT_LINK: + case Enums::HTT_LINK: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__LINK_S__005a57ec, DAT_UserHelpDefinedData::instance .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; @@ -354,11 +356,11 @@ namespace Text { textMemIndex += 2; continue; } - case HTT_INCLUDE: + case Enums::HTT_INCLUDE: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__INCLUDE_S__005a57cc, DAT_UserHelpDefinedData::instance .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; @@ -367,28 +369,28 @@ namespace Text { textMemIndex += 2; continue; } - case HTT_SOUND: + case Enums::HTT_SOUND: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, L"", + MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__SOUND_S__005a57b0, this->soundFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; break; } else { if (param_1 == 1 && -1 < lineY - this->helpContentScrollOffsetY - && lineY - this->helpContentScrollOffsetY < this->dialogContentWidth + && lineY - this->helpContentScrollOffsetY < this->dialogContentHeight && !this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]) { this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] = 1; } textMemIndex += 2; continue; } - case HTT_ENDLINK: + case Enums::HTT_ENDLINK: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - wcscpy(wideTextBuffer, L"<\\LINK>"); + wcscpy(wideTextBuffer, u__LINK__005a53d4); break; } else { currentLinkId = -1; @@ -401,40 +403,40 @@ namespace Text { default: pwVar6 = textMemUnion.text; goto switchD_00460064_caseD_d; - case HTT_STRING: + case Enums::HTT_STRING: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; MACRO_CALL(Global_Func::PrintToDestination)( - wideTextBuffer, L"", this->DAT_PointerToTemporaryTextMemory[textMemIndex]); + wideTextBuffer, u__STRING__d__005a5358, this->DAT_PointerToTemporaryTextMemory[textMemIndex]); textMemIndex += 2; break; } else { textMemIndex += 2; continue; } - case HTT_CENTRE: + case Enums::HTT_CENTRE: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - wcscpy(wideTextBuffer, L""); + wcscpy(wideTextBuffer, u__CENTRE__005a539c); break; } else { centreActive = TRUE; local_120 = TRUE; continue; } - case HTT_ENDCENTRE: + case Enums::HTT_ENDCENTRE: if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - wcscpy(wideTextBuffer, L"<\\CENTRE>"); + wcscpy(wideTextBuffer, u__CENTRE__005a5388); break; } else { centreActive = FALSE; continue; } - case HTT_NEWPARAGRAPH: + case Enums::HTT_NEWPARAGRAPH: if (local_120) { this->lineLayoutTable[lineY].unknown2 = this->lineLayoutTable[lineY].rightBorder - leftPosition; local_120 = centreActive; @@ -473,24 +475,24 @@ namespace Text { local_100 = local_11c; if (param_1 == 1) { ++local_134; - if (0 < this->unknown_0x2396C && 1 < local_134) { + if (0 < this->field51_0x2396c && 1 < local_134) { this->activeHelpHotspotIndex = local_10c + local_11c; local_134 = -10000; if (iVar5 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = iVar5 + -1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } } iVar12 = iVar5; if (iVar5 == this->activeHelpHotspotIndex && param_1 == 1) { local_10c = 0; - if (this->unknown_0x2396C < 0) { + if (this->field51_0x2396c < 0) { this->activeHelpHotspotIndex = DAT_00df3348::instance + local_11c; if (iVar5 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = iVar5 + -1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } local_134 = 0; } @@ -499,15 +501,15 @@ namespace Text { if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - wcscpy(wideTextBuffer, L""); + wcscpy(wideTextBuffer, u__NEWPARAGRAPH__005a5790); break; } continue; - case HTT_TAB: // TODO?: unknown token + case Enums::HTT_TAB: // TODO?: unknown token if (this->helpDialogSubMode == 1) { charColor = 0xff; local_12c = 0; - wcscpy(wideTextBuffer, L""); + wcscpy(wideTextBuffer, u__tab__005a5784); break; } else { if (this->lineLayoutTable[lineY].rightBorder < leftPosition + 30) { @@ -528,13 +530,13 @@ namespace Text { ++local_134; local_100 = local_11c; iVar12 = iVar5; - if (0 < this->unknown_0x2396C && 1 < local_134) { + if (0 < this->field51_0x2396c && 1 < local_134) { this->activeHelpHotspotIndex = local_11c + local_10c; local_134 = -10000; if (iVar5 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = iVar5 + -1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } } local_11c = iVar12; @@ -550,7 +552,7 @@ namespace Text { ++this->topVisibleLineIndex; if (this->lineLayoutTable[this->topVisibleLineIndex].leftBorder == 25 && this->lineLayoutTable[this->topVisibleLineIndex].rightBorder - == this->dialogContentHeight - 25) { + == this->dialogContentWidth - 25) { break; } } while (this->topVisibleLineIndex < 20000); @@ -559,8 +561,8 @@ namespace Text { if (lineStartY < this->helpContentScrollOffsetY) { this->helpContentScrollOffsetY = lineStartY; } - if (lineEndY > this->helpContentScrollOffsetY + this->dialogContentWidth) { - this->helpContentScrollOffsetY = (lineEndY - this->dialogContentWidth) + 5; + if (lineEndY > this->helpContentScrollOffsetY + this->dialogContentHeight) { + this->helpContentScrollOffsetY = (lineEndY - this->dialogContentHeight) + 5; DAT_TextManagerObject::instance.field6_0x18 = 0; return TRUE; } @@ -573,16 +575,16 @@ namespace Text { return TRUE; } DAT_00df3348::instance = local_10c; - if (0 < this->unknown_0x2396C && local_134 == 1) { + if (0 < this->field51_0x2396c && local_134 == 1) { this->activeHelpHotspotIndex = local_10c + local_11c; if (this->activeHelpHotspotIndex > this->customHelpTextLength) { this->activeHelpHotspotIndex = this->customHelpTextLength; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } if (!local_e4 && this->activeHelpHotspotIndex && DAT_00df334c::instance) { --this->activeHelpHotspotIndex; - this->unknown_0x23970 = 0; + this->field52_0x23970 = 0; DAT_TextManagerObject::instance.field6_0x18 = 0; return TRUE; } @@ -613,13 +615,13 @@ namespace Text { ++local_134; local_100 = local_11c; local_11c = local_114; - if (0 < this->unknown_0x2396C && 1 < local_134) { + if (0 < this->field51_0x2396c && 1 < local_134) { this->activeHelpHotspotIndex = iVar5 + local_10c; local_134 = -10000; if (local_114 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = local_114 - 1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } } local_f4 = iVar12 + leftPosition; @@ -644,13 +646,13 @@ namespace Text { ++local_134; local_100 = local_11c; local_11c = local_114 + local_118; - if (0 < this->unknown_0x2396C && 1 < local_134) { + if (0 < this->field51_0x2396c && 1 < local_134) { this->activeHelpHotspotIndex = iVar5 + local_10c; local_134 = -10000; if (local_114 + local_118 <= this->activeHelpHotspotIndex) { this->activeHelpHotspotIndex = local_114 + local_118 - 1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } } do { @@ -674,10 +676,10 @@ namespace Text { iVar5 - this->dialogContentX + local_f8 + leftPosition, currentFontLineHeight + 2)) { if (local_12c) { - this->unknown_0x23964 = local_114 + local_118; - this->unknown_0x23968 = currentLinkId; + this->field49_0x23964 = local_114 + local_118; + this->field50_0x23968 = currentLinkId; } else { - this->unknown_0x23964 = local_114; + this->field49_0x23964 = local_114; } } } @@ -687,12 +689,12 @@ namespace Text { if (param_1 == 1) { if (local_12c) { local_10c = (local_118 - local_11c) + local_114; - if (this->unknown_0x2396C < 0) { + if (this->field51_0x2396c < 0) { this->activeHelpHotspotIndex = DAT_00df3348::instance + local_100; if (this->activeHelpHotspotIndex >= local_11c) { this->activeHelpHotspotIndex = local_11c - 1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } local_134 = 0; MACRO_CALL_MEMBER( @@ -722,10 +724,10 @@ namespace Text { iVar5 - this->dialogContentX + local_f8 + leftPosition, currentFontLineHeight + 2)) { if (local_12c) { - this->unknown_0x23964 = local_114 + local_118; - this->unknown_0x23968 = currentLinkId; + this->field49_0x23964 = local_114 + local_118; + this->field50_0x23968 = currentLinkId; } else { - this->unknown_0x23964 = local_114; + this->field49_0x23964 = local_114; } } } @@ -752,10 +754,10 @@ namespace Text { iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, iVar12 - iVar5, currentFontLineHeight + 2)) { if (local_12c) { - this->unknown_0x23964 = i + local_114; - this->unknown_0x23968 = currentLinkId; + this->field49_0x23964 = i + local_114; + this->field50_0x23968 = currentLinkId; } else { - this->unknown_0x23964 = local_114; + this->field49_0x23964 = local_114; } } } else { @@ -778,12 +780,12 @@ namespace Text { if (param_1 == 1) { local_10c = local_f8 + i; local_134 = 0; - if (this->unknown_0x2396C < 0 && local_12c) { + if (this->field51_0x2396c < 0 && local_12c) { this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; if (this->activeHelpHotspotIndex >= local_11c) { this->activeHelpHotspotIndex = local_11c + -1; } - this->unknown_0x2396C = 0; + this->field51_0x2396c = 0; } local_f0 = TRUE; iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( @@ -792,10 +794,10 @@ namespace Text { iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, iVar12 - iVar5, currentFontLineHeight + 2)) { if (local_12c) { - this->unknown_0x23964 = i + local_114; - this->unknown_0x23968 = currentLinkId; + this->field49_0x23964 = i + local_114; + this->field50_0x23968 = currentLinkId; } else { - this->unknown_0x23964 = local_114; + this->field49_0x23964 = local_114; } } } else { diff --git a/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp b/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp index 1f6bf9c84a..5235981411 100644 --- a/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp +++ b/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp @@ -4,6 +4,7 @@ #include "OpenSHC/OS.func.hpp" #include "OpenSHC/Util/WideCharMultiByteState.func.hpp" #include "OpenSHC/string-literals.hpp" +#include "OpenSHC/wstring-literals.hpp" #include "OpenSHC/Globals/DAT_ResourceManager.hpp" #include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" @@ -11,8 +12,6 @@ namespace OpenSHC { namespace Text { - // TODO: Replace L-strings with str-ptr - // FUNCTION: STRONGHOLDCRUSADER 0x0045F470 FILE* TextEditorState::readCrusaderHelpHlp(LPCSTR searchedPart) { @@ -40,7 +39,7 @@ namespace Text { continue; } wchar_t* hlpPart = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(_File); - if (!hlpPart || MACRO_CALL(OS_Func::__wcsicmp)(L"section", hlpPart)) { + if (!hlpPart || MACRO_CALL(OS_Func::__wcsicmp)(u_section_005a5610, hlpPart)) { continue; } wchar_t* sectionHlpPart = MACRO_CALL_MEMBER(TextEditorState_Func::parseHLPPart, this)(_File); diff --git a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp index d468a9d7c4..fee866c9d8 100644 --- a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp +++ b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp @@ -28,12 +28,12 @@ namespace Text { height += y1 - this->dialogContentY; y1 = this->dialogContentY; } - // Does the naming "dialogContentWidth" fit? Is it related to width? - if (height + y1 > this->dialogContentY + this->dialogContentWidth) { - height = this->dialogContentWidth * 2 - y1; + + if (height + y1 > this->dialogContentY + this->dialogContentHeight) { + height = this->dialogContentHeight * 2 - y1; } int const y2 = y1 + height; - if (y2 >= this->dialogContentY && y1 < this->dialogContentY + this->dialogContentWidth) { + if (y2 >= this->dialogContentY && y1 < this->dialogContentY + this->dialogContentHeight) { int const x2 = x1 + width; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( x1, y1, x2, y1, COL_GREYISH_YELLOW::instance.shortValue); @@ -64,7 +64,7 @@ namespace Text { this->imageHotspotTable[i].yPos - this->helpContentScrollY + this->dialogContentY - this->helpContentScrollOffsetY, boxWidth, boxHeight)) { - this->unknown_0x23968 = this->imageHotspotTable[i].unknown3; + this->field50_0x23968 = this->imageHotspotTable[i].unknown3; } } } diff --git a/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp b/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp index 1ae12edc84..009aa59dc8 100644 --- a/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp +++ b/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp @@ -2,7 +2,9 @@ #include "OpenSHC/IO/ResourceManager.func.hpp" #include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Text/Enums/HelpTextPicturePositionToken.hpp" #include "OpenSHC/string-literals.hpp" +#include "OpenSHC/wstring-literals.hpp" #include "OpenSHC/Globals/DAT_ResourceManager.hpp" #include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" @@ -10,8 +12,6 @@ namespace OpenSHC { namespace Text { - // TODO: Replace L strings with references from a file - // FUNCTION: STRONGHOLDCRUSADER 0x0045DB40 void TextEditorState::saveHelpFileToResource() { @@ -26,89 +26,91 @@ namespace Text { wchar_t const utf16bom = L'\uFEFF'; MACRO_CALL(OS_Func::_fwrite)((void*)&utf16bom, sizeof(wchar_t), 1, _File); - MACRO_CALL(OS_Func::_fwprintf)(_File, L"
\n"); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__HEADER__005a54fc); for (int i = 0; i < this->graphicFileCount; ++i) { - MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n", this->graphicFileNames[i]); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__LOADPIC_S__005a54dc, this->graphicFileNames[i]); } - MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\HEADER>\n"); - MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n"); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__HEADER__005a54c4); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__BODY__005a54b4); for (int i = 0; this->DAT_PointerToTemporaryTextMemory[i];) { HelpTextToken const switchValue = (HelpTextToken)this->DAT_PointerToTemporaryTextMemory[i]; i += 1; switch (switchValue) { - case HTT_PIC: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_PIC: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__PIC__d__005a54a0, this->DAT_PointerToTemporaryTextMemory[i]); i += 1; - switch ((HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[i]) { - case HTT_PIC_LEFT: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"LEFT>"); + switch ((Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[i]) { + case Enums::HTPPT_LEFT: + MACRO_CALL(OS_Func::_fwprintf)(_File, u_LEFT__005a5494); i += 2; break; - case HTT_PIC_RIGHT: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"RIGHT>"); + case Enums::HTPPT_RIGHT: + MACRO_CALL(OS_Func::_fwprintf)(_File, u_RIGHT__005a5484); i += 2; break; - case HTT_PIC_CENTRE: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"CENTRE>"); + case Enums::HTPPT_CENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, u_CENTRE__005a5474); i += 2; break; - case HTT_PIC_HERE: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"HERE>"); + case Enums::HTPPT_HERE: + MACRO_CALL(OS_Func::_fwprintf)(_File, u_HERE__005a5468); default: i += 2; break; } break; - case HTT_FONT: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_FONT: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__FONT__d__005a5454, this->DAT_PointerToTemporaryTextMemory[i]); i += 2; break; - case HTT_COLOUR: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_COLOUR: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__COLOUR_d__005a543c, this->DAT_PointerToTemporaryTextMemory[i]); i += 2; break; - case HTT_LINKCOLOUR: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_LINKCOLOUR: + MACRO_CALL(OS_Func::_fwprintf)( + _File, u__LINKCOLOUR_d__005a541c, this->DAT_PointerToTemporaryTextMemory[i]); i += 2; break; - case HTT_LINK: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", + case Enums::HTT_LINK: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__LINK__S__005a5404, DAT_UserHelpDefinedData::instance.HelpSections[this->DAT_PointerToTemporaryTextMemory[i]]); i += 2; break; - case HTT_INCLUDE: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", + case Enums::HTT_INCLUDE: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__INCLUDE__S__005a53e4, DAT_UserHelpDefinedData::instance.HelpSections[this->DAT_PointerToTemporaryTextMemory[i]]); i += 2; break; - case HTT_ENDLINK: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\LINK>"); + case Enums::HTT_ENDLINK: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__LINK__005a53d4); break; - case HTT_NEWPARAGRAPH: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n\n"); + case Enums::HTT_NEWPARAGRAPH: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__NEWPARAGRAPH__005a53b0); break; - case HTT_CENTRE: - MACRO_CALL(OS_Func::_fwprintf)(_File, L""); + case Enums::HTT_CENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__CENTRE__005a539c); break; - case HTT_ENDCENTRE: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"<\\CENTRE>"); + case Enums::HTT_ENDCENTRE: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__CENTRE__005a5388); break; - case HTT_SOUND: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_SOUND: + MACRO_CALL(OS_Func::_fwprintf)(_File, u__SOUND__d__005a5370, this->DAT_PointerToTemporaryTextMemory[i]); i += 2; break; - case HTT_STRING: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"", this->DAT_PointerToTemporaryTextMemory[i]); + case Enums::HTT_STRING: + MACRO_CALL(OS_Func::_fwprintf)( + _File, u__STRING__d__005a5358, this->DAT_PointerToTemporaryTextMemory[i]); i += 2; break; default: - MACRO_CALL(OS_Func::_fwprintf)(_File, L"%c", (wchar_t)switchValue); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__c_005a5350, (wchar_t)switchValue); break; } } - MACRO_CALL(OS_Func::_fwprintf)(_File, L"\n<\\BODY>\n"); + MACRO_CALL(OS_Func::_fwprintf)(_File, u__BODY__005a533c); MACRO_CALL(OS_Func::_fclose)(_File); } diff --git a/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp b/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp index ba116919b2..eab80e92cd 100644 --- a/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp +++ b/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp @@ -4,12 +4,12 @@ namespace OpenSHC { namespace Text { // FUNCTION: STRONGHOLDCRUSADER 0x0045D080 - void TextEditorState::setHelpWindowBounds(undefined4 x, undefined4 y, undefined4 height, undefined4 width) + void TextEditorState::setHelpWindowBounds(int x, int y, int width, int height) { this->dialogContentX = x; this->dialogContentY = y; - this->dialogContentHeight = height; this->dialogContentWidth = width; + this->dialogContentHeight = height; } } diff --git a/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp b/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp index 72ef3128de..c553407e28 100644 --- a/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp +++ b/src/OpenSHC/Text/TextEditorState/setTextRenderingLogic.cpp @@ -15,18 +15,18 @@ namespace Text { if (this->helpDialogVariant != 1) { MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRect, DAT_TextureRenderCoreObject::ptr)(this->dialogContentX, this->dialogContentY, - this->dialogContentHeight + this->dialogContentX, this->dialogContentWidth + this->dialogContentY); + this->dialogContentWidth + this->dialogContentX, this->dialogContentHeight + this->dialogContentY); MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setScreenMenuSurfaceHeightRange, DAT_TextureRenderCoreObject::ptr)( - this->dialogContentY, this->dialogContentWidth + this->dialogContentY); + this->dialogContentY, this->dialogContentHeight + this->dialogContentY); DAT_TextureRenderCoreObject::instance.drawBufferChoiceValue = Rendering::Enums::RT_SCREEN_MENU; } else { MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::setRenderingRect, DAT_TextureRenderCoreObject::ptr)(this->dialogContentX, this->dialogContentY, - this->dialogContentHeight + this->dialogContentX, this->dialogContentWidth + this->dialogContentY); + this->dialogContentWidth + this->dialogContentX, this->dialogContentHeight + this->dialogContentY); MACRO_CALL_MEMBER( UI::Rendering::TextureRenderCore_Func::setMapSurfaceHeightRange, DAT_TextureRenderCoreObject::ptr)( - this->dialogContentY, this->dialogContentWidth + this->dialogContentY); + this->dialogContentY, this->dialogContentHeight + this->dialogContentY); DAT_TextManagerObject::instance.textSurfaceTarget = Rendering::Enums::RT_MAP_GAME; DAT_PencilRenderCore::instance.surfaceTarget = Rendering::Enums::RT_MAP_GAME; DAT_TextureRenderCoreObject::instance.currentRenderSurfaceIdentifierUnk_0x8 = Rendering::Enums::RT_MAP_GAME; From d512f74e4a32cc89dfb98a21ec4e5af073b16a58 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Sun, 27 Sep 2026 03:43:43 +0200 Subject: [PATCH 43/44] reimplement: SHC_3BB0A8C1_0x0045FDC0 70.1% --- IMPLEMENTATION_CHEAT_SHEET.md | 3 +- src/OpenSHC/Text/TextEditorState.hpp | 6 - .../TextEditorState/drawBorderStyle0x20.cpp | 3 - .../getWideCharOrWideCharPointer.cpp | 1 - .../initializeAndLayoutHelpText.cpp | 2 +- .../processHelpRichTextTokens.cpp | 924 +++++++++--------- .../renderHelpImageHotspots.cpp | 4 +- status/addresses-SHC-3BB0A8C1.txt | 2 +- 8 files changed, 456 insertions(+), 489 deletions(-) diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index afc4ac6615..e29a3b2225 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -516,7 +516,8 @@ translation unit. ### Parameters Parameters might not be pushed like normal in certain cases. -Usually, if two functions are followed by each other, the parameters are pushed for the first function, then the call is executed and then parameters for the second function are pushed. If parameters for the second function are pushed before the first call, it might indicate that the first call was executed in place of a variable, to directly feed the return into the second function. +Usually, if two functions are followed by each other, the parameters are pushed for the first function, then the call is executed and then parameters for the second function are pushed. If parameters for the second function are pushed before the first call, it might indicate that the first call was executed in place of a variable, to directly feed the return into the second function. +This possibility is actually universal. If a computation of a value happens between pushes of parameters, it makes it likely the value was computed in-place. The other way around is also possible. If a computed value is created completely or partially before any push, it might have been a temporary. ### Implicit functions diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 7135598688..5c547d91c6 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -20,12 +20,6 @@ namespace OpenSHC { namespace Text { - struct LineLayout { - short leftBorder; - short rightBorder; - short unknown2; - }; - using OpenSHC::Text::ImageHotspot; using OpenSHC::Text::LineLayout; using OpenSHC::Text::Enums::HelpTextToken; diff --git a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp index bb01a0ba2e..81cf0d158f 100644 --- a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp +++ b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp @@ -17,9 +17,6 @@ namespace Text { this->dialogWidth = dialogWidth; this->dialogHeight = dialogHeight; - // NOTE: dialogWidth is used to compute the content height and vice versa, no idea if something was switched; - // also, the required order feels strange, maybe they used a RECT struct or macro - // FIXME: ContentHeight and ContentWidth or the dialogWidth and dialogHeight are swapped int const contentX = this->dialogX + DAT_00df2964::instance; int const contentY = this->dialogY + DAT_00df296c::instance; int const contentHeight = this->dialogHeight - INT_00df2970::instance; diff --git a/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp b/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp index 7e28ededd5..c6a74bae41 100644 --- a/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp +++ b/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp @@ -6,7 +6,6 @@ namespace OpenSHC { namespace Text { // NOTE: Return is essentially a "union", however, it needs to be a value for the proper structure - // Also, it might be likely that this function is "known" by its only user "processHelpRichTextTokens" // FUNCTION: STRONGHOLDCRUSADER 0x0045D3C0 uint TextEditorState::getWideCharOrWideCharPointer(int* param_1) diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp index ac6882fef2..01f33a5114 100644 --- a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp +++ b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp @@ -9,7 +9,7 @@ namespace Text { for (int i = 0; i < 20000; ++i) { this->lineLayoutTable[i].leftBorder = 25; this->lineLayoutTable[i].rightBorder = this->dialogContentWidth - 25; - this->lineLayoutTable[i].unknown2 = 0; + this->lineLayoutTable[i].widthForCentering = 0; } // Adds vertical space at start for (int i = 0; i < 4; ++i) { diff --git a/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp index 760bec549c..ca3e75a9ca 100644 --- a/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp +++ b/src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp @@ -19,6 +19,16 @@ #include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" #include "OpenSHC/Globals/DAT_UserHelpDefinedData.hpp" +// Even now, part of the logic after the L' ' is pulled into the switch, but not the right way +// the position after endlink might be related to being the first position that has no +2 on the the memindex, but still +// sets the wideBuffer; no idea how to trigger it, though + +// It is possible to move the pulled section by messing with certain branches, however, this likely really requires the +// right structure over all cases, it might even involve mixed structures, since a human wrote it + +// most unmarked things are related to the alternate help text, which only seems to be active for the map editor text, +// which is strange. So either this is a left over, or maybe the help text editor hat a switch for this in some way + namespace OpenSHC { namespace Text { @@ -32,28 +42,20 @@ namespace Text { // FUNCTION: STRONGHOLDCRUSADER 0x0045FDC0 int TextEditorState::processHelpRichTextTokens(int param_1) { - int iVar5; - wchar_t* pwVar6; - int iVar12; - int dVar14; - int iVar17; - int local_12c; - int local_118; - int local_114; - int local_104; - int local_f8; - int local_f4; wchar_t wideTextBuffer[100]; + + int local_f8; + int currentLinkId = -1; int textMemIndex = 0; FontSizeClass* currentFontClass = DAT_TextManagerObject::instance.fontSizeClassArray + 17; - int currentFontLineHeight = DAT_TextManagerObject::instance.fontSizeClassArray[17].lineHeight_0x14; + int currentFontLineHeight = currentFontClass->lineHeight_0x14; BOOL local_f0 = FALSE; BGR24 color = 0xccfaff; BGR24 linkColor = 0x8bcf84; int imageCount = -1; BOOL centreActive = FALSE; - BOOL local_120 = FALSE; + BOOL centerCurrentLine = FALSE; int lineStartY = 0; int lineEndY = 0; int local_11c = 0; @@ -68,7 +70,7 @@ namespace Text { return 1; } this->field49_0x23964 = -1; - this->field50_0x23968 = -1; + this->currentLinkId = -1; if (this->field51_0x2396c) { DAT_00df334c::instance = 1; } @@ -78,30 +80,38 @@ namespace Text { if (this->activeHelpHotspotIndex > this->customHelpTextLength) { this->activeHelpHotspotIndex = this->customHelpTextLength; } - int leftPosition; int lineY = -1; + int leftPosition; do { leftPosition = this->lineLayoutTable[++lineY].leftBorder; } while (leftPosition == -1); - while (true) { - iVar5 = textMemIndex; - BGR24 charColor = color; - local_12c = 1; + + bool abortProcessing; + do { + abortProcessing = false; + + TextMemUnion textToRender; + int local_114; + BGR24 charColor; + // false if text debug view token handled (this->helpDialogSubMode == 1), maybe related to input? + BOOL local_12c; + + charColor = color; + local_12c = TRUE; if (0 <= currentLinkId) { charColor = linkColor; } local_114 = textMemIndex; - TextMemUnion textMemUnion; - textMemUnion.value + textToRender.value = MACRO_CALL_MEMBER(TextEditorState_Func::getWideCharOrWideCharPointer, this)(&textMemIndex); - if (this->useAlternateHelpTab && textMemUnion.value < L' ' - && textMemUnion.helpToken != Enums::HTT_NEWPARAGRAPH && iVar5 == this->activeHelpHotspotIndex) { - lineEndY = lineY + currentFontLineHeight; + if (this->useAlternateHelpTab && textToRender.value < L' ' + && textToRender.helpToken != Enums::HTT_NEWPARAGRAPH && local_114 == this->activeHelpHotspotIndex) { lineStartY = lineY; + lineEndY = lineY + currentFontLineHeight; if (param_1 == 1) { int xModify = 0; - if (local_120) { - xModify = this->lineLayoutTable[lineY].unknown2 / 2; + if (centerCurrentLine) { + xModify = this->lineLayoutTable[lineY].widthForCentering / 2; } local_10c = local_114 - local_11c; if (this->field51_0x2396c < 0) { @@ -112,100 +122,101 @@ namespace Text { this->field51_0x2396c = 0; } local_134 = 0; + int xPos = this->dialogContentX + xModify; + int yPos = this->dialogContentY - this->helpContentScrollOffsetY; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( - this->dialogContentX + xModify - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, - this->dialogContentX + xModify - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + xPos + leftPosition - 1, yPos + lineY - 1, xPos + leftPosition - 1, yPos + lineEndY + 1, COL_DARK_LIME::instance.shortValue); + xPos = this->dialogContentX + xModify; + yPos = this->dialogContentY - this->helpContentScrollOffsetY; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( - this->dialogContentX + xModify + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, - this->dialogContentX + xModify + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + xPos + leftPosition, yPos + lineY - 1, xPos + leftPosition, yPos + lineEndY + 1, COL_DARK_LIME::instance.shortValue); local_e4 = TRUE; } } - iVar17 = local_11c; - switch (textMemUnion.helpToken) { - case Enums::HTT_PIC: + switch (textToRender.helpToken) { + case Enums::HTT_PIC: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__PIC__d__S__005a583c, this->DAT_PointerToTemporaryTextMemory[textMemIndex], this->graphicFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); + Enums::HelpTextPicturePositionToken positionToken + = (Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1]; ++textMemIndex; - switch ((Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex]) { + switch (positionToken) { case Enums::HTPPT_LEFT: wcscat(wideTextBuffer, u_LEFT__005a5494); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; case Enums::HTPPT_RIGHT: wcscat(wideTextBuffer, u_RIGHT__005a5484); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; case Enums::HTPPT_CENTRE: wcscat(wideTextBuffer, u_CENTRE__005a5474); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; case Enums::HTPPT_HERE: wcscat(wideTextBuffer, u_HERE__005a5468); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; default: textMemIndex += 2; + textToRender.text = wideTextBuffer; break; } break; - } else { - ++imageCount; - if (param_1 == 1) { - if (this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] != 3) { - textMemIndex += 3; - continue; - } - } else { - if (param_1 - || (imageCount != this->imageHotspotCount - && this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] != 3)) { - textMemIndex += 3; - continue; - } - if (imageCount == this->imageHotspotCount) { - this->imageHotspotTable[this->imageHotspotCount].yPos = lineY + 25; - this->imageHotspotTable[this->imageHotspotCount].imageRelated - = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; - this->imageHotspotTable[this->imageHotspotCount].unknown3 = currentLinkId; - } + } + ++imageCount; + + bool validImageIndex = false; + int imageIndex; + if (param_1 == 1 && this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] == Enums::HTPPT_HERE) { + imageIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + validImageIndex = true; + } else if (!param_1 + && (imageCount == this->imageHotspotCount + || this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1] == Enums::HTPPT_HERE)) { + imageIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + if (imageCount == this->imageHotspotCount) { + this->imageHotspotTable[this->imageHotspotCount].yPos = lineY + 25; + this->imageHotspotTable[this->imageHotspotCount].imageIndex = imageIndex; + this->imageHotspotTable[this->imageHotspotCount].linkId = currentLinkId; } + validImageIndex = true; + } + if (validImageIndex) { Enums::HelpTextPicturePositionToken positionToken = (Enums::HelpTextPicturePositionToken)this->DAT_PointerToTemporaryTextMemory[textMemIndex + 1]; - int imageHeight = DAT_TextureRenderCoreObject::instance - .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] - .height; - int imageWidth = DAT_TextureRenderCoreObject::instance - .loadedGfxArray[99 - this->DAT_PointerToTemporaryTextMemory[textMemIndex]] - .width; + ++textMemIndex; + int imageWidth = DAT_TextureRenderCoreObject::instance.loadedGfxArray[99 - imageIndex].width; + int imageHeight = DAT_TextureRenderCoreObject::instance.loadedGfxArray[99 - imageIndex].height; switch (positionToken) { - case Enums::HTPPT_LEFT: + case Enums::HTPPT_LEFT: { this->imageHotspotTable[this->imageHotspotCount].xPos = this->lineLayoutTable[lineY].leftBorder; + int newLeftBorder = this->lineLayoutTable[lineY].leftBorder + 25 + imageWidth; for (int i = 0; i < imageHeight + 50; ++i) { - this->lineLayoutTable[lineY + i].rightBorder - = this->lineLayoutTable[lineY].leftBorder + 25 + imageWidth; + this->lineLayoutTable[lineY + i].leftBorder = newLeftBorder; } break; - case Enums::HTPPT_RIGHT: + } + case Enums::HTPPT_RIGHT: { this->imageHotspotTable[this->imageHotspotCount].xPos = this->lineLayoutTable[lineY].rightBorder - imageWidth; + int newRightBorder = this->lineLayoutTable[lineY].rightBorder - imageWidth - 25; for (int i = 0; i < imageHeight + 50; ++i) { - this->lineLayoutTable[lineY + i].rightBorder - = this->lineLayoutTable[lineY].rightBorder - imageWidth - 25; - this->lineLayoutTable[lineY + i].leftBorder = -1; + this->lineLayoutTable[lineY + i].rightBorder = newRightBorder; } break; + } case Enums::HTPPT_CENTRE: this->imageHotspotTable[this->imageHotspotCount].xPos = (this->dialogContentWidth - imageWidth) / 2; @@ -213,339 +224,350 @@ namespace Text { this->lineLayoutTable[lineY + i].leftBorder = -1; } break; - case Enums::HTPPT_HERE: - imageWidth += 3; - if (this->lineLayoutTable[lineY].rightBorder < imageWidth + leftPosition) { + case Enums::HTPPT_HERE: { + int const hereWidth = imageWidth + 3; + if (hereWidth + leftPosition > this->lineLayoutTable[lineY].rightBorder) { local_f0 = FALSE; - if (local_120) { - this->lineLayoutTable[lineY].unknown2 + if (centerCurrentLine) { + this->lineLayoutTable[lineY].widthForCentering = this->lineLayoutTable[lineY].rightBorder - leftPosition; - local_120 = centreActive; + centerCurrentLine = centreActive; } do { lineY += currentFontLineHeight + 1; do { - leftPosition = this->lineLayoutTable[lineY++].leftBorder; + leftPosition = this->lineLayoutTable[++lineY].leftBorder; } while (leftPosition == -1); - } while (this->lineLayoutTable[lineY].rightBorder < leftPosition + imageWidth); + } while (leftPosition + hereWidth > this->lineLayoutTable[lineY].rightBorder); if (this->useAlternateHelpTab && param_1 == 1) { - ++local_134; local_100 = local_11c; local_11c = local_114; - if (0 < this->field51_0x2396c && 1 < local_134) { - this->activeHelpHotspotIndex = iVar17 + local_10c; + ++local_134; + if (0 < this->field51_0x2396c && 2 <= local_134) { local_134 = -10000; - if (local_114 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = local_114 + -1; + this->activeHelpHotspotIndex = local_100 + local_10c; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } this->field51_0x2396c = 0; } } currentFontLineHeight = currentFontClass->lineHeight_0x14; } - if (currentFontLineHeight < imageHeight) { + if (imageHeight > currentFontLineHeight) { currentFontLineHeight = imageHeight; } - leftPosition += imageWidth; + leftPosition += hereWidth; if (param_1 != 1 && imageCount == this->imageHotspotCount) { - this->imageHotspotTable[this->imageHotspotCount].xPos = leftPosition - imageWidth; + this->imageHotspotTable[this->imageHotspotCount].xPos = leftPosition - hereWidth; this->imageHotspotTable[this->imageHotspotCount].yPos = lineY; ++this->imageHotspotCount; } break; } - textMemIndex += 3; - if (positionToken == Enums::HTPPT_HERE || param_1) { - continue; } - ++this->imageHotspotCount; - DAT_TextManagerObject::instance.field6_0x18 = 0; - return FALSE; + textMemIndex += 2; + if (positionToken != Enums::HTPPT_HERE && !param_1) { + ++this->imageHotspotCount; + DAT_TextManagerObject::instance.helpTextLinkActive = FALSE; + abortProcessing = true; + // continue; + } + } else { + textMemIndex += 3; } - case Enums::HTT_FONT: + break; + } + case Enums::HTT_FONT: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)( wideTextBuffer, u__FONT__d__005a5454, this->DAT_PointerToTemporaryTextMemory[textMemIndex]); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - int fontSize = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; - if (fontSize < 15) { - fontSize += 5; - } - textMemIndex = textMemIndex + 2; - currentFontClass = DAT_TextManagerObject::instance.fontSizeClassArray + fontSize; - dVar14 = DAT_TextManagerObject::instance.fontSizeClassArray[fontSize].lineHeight_0x14; - if (currentFontLineHeight < dVar14 || !local_f0) { - currentFontLineHeight = dVar14; - } - continue; } - case Enums::HTT_COLOUR: + int fontSize = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + if (fontSize < 15) { + fontSize += 5; + } + textMemIndex += 2; + currentFontClass = &DAT_TextManagerObject::instance.fontSizeClassArray[fontSize]; + if (currentFontClass->lineHeight_0x14 > currentFontLineHeight || !local_f0) { + currentFontLineHeight = currentFontClass->lineHeight_0x14; + } + break; + } + case Enums::HTT_COLOUR: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__COLOUR__S__005a5824, DAT_UserHelpDefinedData::instance .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .name_0x0); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - if (param_1 == 1) { - int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + } + if (param_1 == 1) { + int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; - uint colorRed; - uint colorGreen; - uint colorBlue; - if (this->helpDialogVariant == 2 && colorIndex == 1) { - colorRed = 0xd7; - colorGreen = 0xd2; - colorBlue = 0xa4; - } else { - colorRed = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4; - colorGreen = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8; - colorBlue = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc; - } - textMemIndex += 2; - color = ((colorBlue << 16) & 0xff0000) | ((colorGreen << 8) & 0x00ff00) | colorRed & 0x0000ff; + uint colorRed; + uint colorGreen; + uint colorBlue; + if (this->helpDialogVariant == 2 && colorIndex == 1) { + colorRed = 0xd7; + colorGreen = 0xd2; + colorBlue = 0xa4; } else { - textMemIndex += 2; + colorRed = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4; + colorGreen = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8; + colorBlue = DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc; } - continue; + textMemIndex += 2; + color = RGB(colorRed, colorGreen, colorBlue); + } else { + textMemIndex += 2; } - case Enums::HTT_LINKCOLOUR: + break; + } + case Enums::HTT_LINKCOLOUR: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__LINKCOLOUR__S__005a5804, DAT_UserHelpDefinedData::instance .field6_0x7a16c[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] .name_0x0); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; + } + if (param_1 == 1) { + int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + textMemIndex += 2; + linkColor = RGB(DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4, + DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8, + DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc); } else { - if (param_1 == 1) { - int const colorIndex = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; - textMemIndex += 2; - linkColor - = ((DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].b_0xc << 16) & 0xff0000) - | ((DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].g_0x8 << 8) & 0x00ff00) - | DAT_UserHelpDefinedData::instance.field6_0x7a16c[colorIndex].r_0x4 & 0x0000ff; - } else { - textMemIndex += 2; - } - continue; + textMemIndex += 2; } - case Enums::HTT_LINK: + break; + } + case Enums::HTT_LINK: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__LINK_S__005a57ec, DAT_UserHelpDefinedData::instance .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - currentLinkId = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; - if (param_1 == 1) { - DAT_TextManagerObject::instance.field6_0x18 = 1; - } - textMemIndex += 2; - continue; } - case Enums::HTT_INCLUDE: + currentLinkId = this->DAT_PointerToTemporaryTextMemory[textMemIndex]; + if (param_1 == 1) { + DAT_TextManagerObject::instance.helpTextLinkActive = TRUE; + } + textMemIndex += 2; + break; + } + case Enums::HTT_INCLUDE: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__INCLUDE_S__005a57cc, DAT_UserHelpDefinedData::instance .HelpSections[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - textMemIndex += 2; - continue; } - case Enums::HTT_SOUND: + textMemIndex += 2; + break; + } + case Enums::HTT_SOUND: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)(wideTextBuffer, u__SOUND_S__005a57b0, this->soundFileNames[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - if (param_1 == 1 && -1 < lineY - this->helpContentScrollOffsetY - && lineY - this->helpContentScrollOffsetY < this->dialogContentHeight + } + if (param_1 == 1) { + int const visibleY = lineY - this->helpContentScrollOffsetY; + if (0 <= visibleY && visibleY < this->dialogContentHeight && !this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]]) { this->soundFilePlayedFlags[this->DAT_PointerToTemporaryTextMemory[textMemIndex]] = 1; } - textMemIndex += 2; - continue; } - case Enums::HTT_ENDLINK: + textMemIndex += 2; + break; + } + case Enums::HTT_ENDLINK: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; wcscpy(wideTextBuffer, u__LINK__005a53d4); + textToRender.text = wideTextBuffer; break; - } else { - currentLinkId = -1; - if (param_1 == 1) { - DAT_TextManagerObject::instance.field6_0x18 = 0; - } - continue; } - case (wchar_t*)13: // unknown case? - default: - pwVar6 = textMemUnion.text; - goto switchD_00460064_caseD_d; - case Enums::HTT_STRING: + currentLinkId = -1; + if (param_1 == 1) { + DAT_TextManagerObject::instance.helpTextLinkActive = FALSE; + } + break; + } + case Enums::HTT_STRING: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; MACRO_CALL(Global_Func::PrintToDestination)( wideTextBuffer, u__STRING__d__005a5358, this->DAT_PointerToTemporaryTextMemory[textMemIndex]); textMemIndex += 2; + textToRender.text = wideTextBuffer; break; - } else { - textMemIndex += 2; - continue; } - case Enums::HTT_CENTRE: + textMemIndex += 2; + break; + } + case Enums::HTT_CENTRE: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; wcscpy(wideTextBuffer, u__CENTRE__005a539c); + textToRender.text = wideTextBuffer; break; - } else { - centreActive = TRUE; - local_120 = TRUE; - continue; } - case Enums::HTT_ENDCENTRE: + centreActive = TRUE; + centerCurrentLine = TRUE; + break; + } + case Enums::HTT_ENDCENTRE: { if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; wcscpy(wideTextBuffer, u__CENTRE__005a5388); + textToRender.text = wideTextBuffer; break; - } else { - centreActive = FALSE; - continue; } - case Enums::HTT_NEWPARAGRAPH: - if (local_120) { - this->lineLayoutTable[lineY].unknown2 = this->lineLayoutTable[lineY].rightBorder - leftPosition; - local_120 = centreActive; + centreActive = FALSE; + break; + } + case Enums::HTT_NEWPARAGRAPH: { + if (centerCurrentLine) { + this->lineLayoutTable[lineY].widthForCentering + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + centerCurrentLine = centreActive; } - if (this->useAlternateHelpTab && iVar5 == this->activeHelpHotspotIndex) { - lineEndY = currentFontLineHeight + lineY; - iVar12 = 0; + if (this->useAlternateHelpTab && local_114 == this->activeHelpHotspotIndex) { lineStartY = lineY; + lineEndY = currentFontLineHeight + lineY; if (param_1 == 1) { - if (local_120) { - iVar12 = this->lineLayoutTable[lineY].unknown2 / 2; + int xModify = 0; + if (centerCurrentLine) { + xModify = this->lineLayoutTable[lineY].widthForCentering / 2; } + int xPos = this->dialogContentX + xModify; + int yPos = this->dialogContentY - this->helpContentScrollOffsetY; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( - this->dialogContentX + iVar12 - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, - this->dialogContentX + iVar12 - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, - COL_DARK_LIME::instance.shortValue); + xPos - 1 + leftPosition, yPos - 1 + lineStartY, xPos - 1 + leftPosition, + yPos + 1 + lineEndY, COL_DARK_LIME::instance.shortValue); + xPos = this->dialogContentX + xModify; + yPos = this->dialogContentY - this->helpContentScrollOffsetY; MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( - this->dialogContentX + iVar12 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, - this->dialogContentX + iVar12 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, + xPos + leftPosition, yPos - 1 + lineStartY, xPos + leftPosition, yPos + 1 + lineEndY, COL_DARK_LIME::instance.shortValue); local_e4 = TRUE; } } - lineY += 3 + currentFontLineHeight; local_f0 = FALSE; + lineY += 3 + currentFontLineHeight; do { - leftPosition = this->lineLayoutTable[lineY++].leftBorder; + leftPosition = this->lineLayoutTable[++lineY].leftBorder; } while (leftPosition == -1); currentFontLineHeight = currentFontClass->lineHeight_0x14; - iVar12 = local_11c; - if (this->useAlternateHelpTab != 0) { + + if (this->useAlternateHelpTab) { local_100 = local_11c; + local_11c = local_114; if (param_1 == 1) { ++local_134; - if (0 < this->field51_0x2396c && 1 < local_134) { - this->activeHelpHotspotIndex = local_10c + local_11c; + if (0 < this->field51_0x2396c && 2 <= local_134) { local_134 = -10000; - if (iVar5 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = iVar5 + -1; + this->activeHelpHotspotIndex = local_10c + local_100; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } this->field51_0x2396c = 0; } } - iVar12 = iVar5; - if (iVar5 == this->activeHelpHotspotIndex && param_1 == 1) { + if (local_11c == this->activeHelpHotspotIndex && param_1 == 1) { local_10c = 0; if (this->field51_0x2396c < 0) { - this->activeHelpHotspotIndex = DAT_00df3348::instance + local_11c; - if (iVar5 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = iVar5 + -1; + this->activeHelpHotspotIndex = DAT_00df3348::instance + local_100; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } this->field51_0x2396c = 0; } local_134 = 0; } } - local_11c = iVar12; if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; wcscpy(wideTextBuffer, u__NEWPARAGRAPH__005a5790); + textToRender.text = wideTextBuffer; break; } - continue; - case Enums::HTT_TAB: // TODO?: unknown token + break; + } + case Enums::HTT_TAB: { // TODO?: unknown token if (this->helpDialogSubMode == 1) { charColor = 0xff; - local_12c = 0; + local_12c = FALSE; wcscpy(wideTextBuffer, u__tab__005a5784); + textToRender.text = wideTextBuffer; break; - } else { - if (this->lineLayoutTable[lineY].rightBorder < leftPosition + 30) { - local_f0 = FALSE; - if (local_120) { - this->lineLayoutTable[lineY].unknown2 - = this->lineLayoutTable[lineY].rightBorder - leftPosition; - local_120 = centreActive; - } + } + if (leftPosition + 30 > this->lineLayoutTable[lineY].rightBorder) { + local_f0 = FALSE; + if (centerCurrentLine) { + this->lineLayoutTable[lineY].widthForCentering + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + centerCurrentLine = centreActive; + } + do { + lineY += currentFontLineHeight + 1; do { - lineY += currentFontLineHeight + 1; - do { - leftPosition = this->lineLayoutTable[lineY++].leftBorder; - } while (leftPosition == -1); - } while (this->lineLayoutTable[lineY].rightBorder < leftPosition + 30); - iVar12 = local_11c; - if (this->useAlternateHelpTab && param_1 == 1) { - ++local_134; - local_100 = local_11c; - iVar12 = iVar5; - if (0 < this->field51_0x2396c && 1 < local_134) { - this->activeHelpHotspotIndex = local_11c + local_10c; - local_134 = -10000; - if (iVar5 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = iVar5 + -1; - } - this->field51_0x2396c = 0; + leftPosition = this->lineLayoutTable[++lineY].leftBorder; + } while (leftPosition == -1); + } while (leftPosition + 30 > this->lineLayoutTable[lineY].rightBorder); + + if (this->useAlternateHelpTab && param_1 == 1) { + local_100 = local_11c; + local_11c = local_114; + ++local_134; + if (0 < this->field51_0x2396c && 2 <= local_134) { + local_134 = -10000; + this->activeHelpHotspotIndex = local_100 + local_10c; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } + this->field51_0x2396c = 0; } - local_11c = iVar12; - currentFontLineHeight = currentFontClass->lineHeight_0x14; } - leftPosition += 30; - continue; + currentFontLineHeight = currentFontClass->lineHeight_0x14; } - case (wchar_t*)0: // TODO?: unknown token, or just NULL, meaning end? + leftPosition += 30; + break; + } + case (wchar_t*)0: { // TODO?: unknown token, or just NULL, meaning end? if (param_1 == 0) { this->topVisibleLineIndex = lineY + currentFontLineHeight - 1; do { @@ -563,255 +585,209 @@ namespace Text { } if (lineEndY > this->helpContentScrollOffsetY + this->dialogContentHeight) { this->helpContentScrollOffsetY = (lineEndY - this->dialogContentHeight) + 5; - DAT_TextManagerObject::instance.field6_0x18 = 0; + DAT_TextManagerObject::instance.helpTextLinkActive = FALSE; return TRUE; } } - DAT_TextManagerObject::instance.field6_0x18 = 0; - return TRUE; - } - if (!this->useAlternateHelpTab) { - DAT_TextManagerObject::instance.field6_0x18 = 0; - return TRUE; - } - DAT_00df3348::instance = local_10c; - if (0 < this->field51_0x2396c && local_134 == 1) { - this->activeHelpHotspotIndex = local_10c + local_11c; - if (this->activeHelpHotspotIndex > this->customHelpTextLength) { - this->activeHelpHotspotIndex = this->customHelpTextLength; + } else if (this->useAlternateHelpTab) { + DAT_00df3348::instance = local_10c; + if (0 < this->field51_0x2396c && local_134 == 1) { + this->activeHelpHotspotIndex = local_10c + local_11c; + if (this->activeHelpHotspotIndex > this->customHelpTextLength) { + this->activeHelpHotspotIndex = this->customHelpTextLength; + } + this->field51_0x2396c = 0; } - this->field51_0x2396c = 0; - } - if (!local_e4 && this->activeHelpHotspotIndex && DAT_00df334c::instance) { - --this->activeHelpHotspotIndex; - this->field52_0x23970 = 0; - DAT_TextManagerObject::instance.field6_0x18 = 0; - return TRUE; + if (!local_e4 && this->activeHelpHotspotIndex && DAT_00df334c::instance) { + --this->activeHelpHotspotIndex; + this->field52_0x23970 = 0; + DAT_TextManagerObject::instance.helpTextLinkActive = FALSE; + return TRUE; + } + DAT_00df334c::instance = 0; } - DAT_00df334c::instance = 0; - DAT_TextManagerObject::instance.field6_0x18 = 0; + DAT_TextManagerObject::instance.helpTextLinkActive = FALSE; return TRUE; } - // NOTE: This is either the local text buffer, or the text directly from the text memory... - pwVar6 = wideTextBuffer; - switchD_00460064_caseD_d: - if (0x1f < (int)pwVar6) { - iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWidthOfWideText, currentFontClass)( - pwVar6, wcslen((wchar_t*)pwVar6)); - iVar5 = local_11c; - local_f4 = leftPosition + iVar12; - if (this->lineLayoutTable[lineY].rightBorder < local_f4) { - local_f0 = FALSE; - if (local_120) { - this->lineLayoutTable[lineY].unknown2 = this->lineLayoutTable[lineY].rightBorder - leftPosition; - local_120 = centreActive; - } - lineY += 1 + currentFontLineHeight; - do { - leftPosition = this->lineLayoutTable[lineY++].leftBorder; - } while (leftPosition == -1); - currentFontLineHeight = currentFontClass->lineHeight_0x14; - if (this->useAlternateHelpTab) { - ++local_134; - local_100 = local_11c; - local_11c = local_114; - if (0 < this->field51_0x2396c && 1 < local_134) { - this->activeHelpHotspotIndex = iVar5 + local_10c; - local_134 = -10000; - if (local_114 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = local_114 - 1; - } - this->field51_0x2396c = 0; + } + if (textToRender.value < L' ') { + continue; + } + + int textWidth = MACRO_CALL_MEMBER(FontSizeClass_Func::getWidthOfWideText, currentFontClass)( + textToRender.text, wcslen(textToRender.text)); + if (leftPosition + textWidth > this->lineLayoutTable[lineY].rightBorder) { + local_f0 = FALSE; + if (centerCurrentLine) { + this->lineLayoutTable[lineY].widthForCentering + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + centerCurrentLine = centreActive; + } + lineY += 1 + currentFontLineHeight; + do { + leftPosition = this->lineLayoutTable[++lineY].leftBorder; + } while (leftPosition == -1); + currentFontLineHeight = currentFontClass->lineHeight_0x14; + if (this->useAlternateHelpTab) { + ++local_134; + local_100 = local_11c; + local_11c = local_114; + if (0 < this->field51_0x2396c && 2 <= local_134) { + local_134 = -10000; + this->activeHelpHotspotIndex = local_100 + local_10c; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } + this->field51_0x2396c = 0; } - local_f4 = iVar12 + leftPosition; - if (this->lineLayoutTable[lineY].rightBorder < (int)local_f4) { - local_f8 = 0; - if (local_120) { - local_f8 = this->lineLayoutTable[lineY].unknown2 / 2; - } - int const wideStrLength = wcslen((wchar_t*)pwVar6); - for (local_118 = 0; local_118 < wideStrLength; ++local_118) { - int wideCharWidth = MACRO_CALL_MEMBER( - FontSizeClass_Func::getWideCharWidth, currentFontClass)(textMemUnion.text[local_118]); - while (this->lineLayoutTable[lineY].rightBorder < leftPosition + wideCharWidth) { - iVar5 = local_11c; - if (local_120) { - this->lineLayoutTable[lineY].unknown2 - = this->lineLayoutTable[lineY].rightBorder - leftPosition; - local_120 = centreActive; - } - lineY += currentFontLineHeight + 1; - if (this->useAlternateHelpTab && param_1 == 1) { - ++local_134; - local_100 = local_11c; - local_11c = local_114 + local_118; - if (0 < this->field51_0x2396c && 1 < local_134) { - this->activeHelpHotspotIndex = iVar5 + local_10c; - local_134 = -10000; - if (local_114 + local_118 <= this->activeHelpHotspotIndex) { - this->activeHelpHotspotIndex = local_114 + local_118 - 1; - } - this->field51_0x2396c = 0; - } - } - do { - leftPosition = this->lineLayoutTable[lineY++].leftBorder; - } while (leftPosition == -1); - if (local_120) { - local_f8 = this->lineLayoutTable[lineY].unknown2 / 2; - } + } + if (leftPosition + textWidth > this->lineLayoutTable[lineY].rightBorder) { + local_f8 = 0; + if (centerCurrentLine) { + local_f8 = this->lineLayoutTable[lineY].widthForCentering / 2; + } + int wordLength = wcslen(textToRender.text); + for (int i = 0; i < wordLength; ++i) { + int wideCharWidth = MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( + textToRender.text[i]); + while (leftPosition + wideCharWidth > this->lineLayoutTable[lineY].rightBorder) { + + if (centerCurrentLine) { + this->lineLayoutTable[lineY].widthForCentering + = this->lineLayoutTable[lineY].rightBorder - leftPosition; + centerCurrentLine = centreActive; } - if (!this->useAlternateHelpTab || local_114 + local_118 != this->activeHelpHotspotIndex) { - if (param_1 == 1) { - iVar5 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( - textMemUnion.text[local_118], this->dialogContentX + local_f8 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + lineY, charColor, 0); - local_f0 = TRUE; - if (MACRO_CALL_MEMBER( - Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( - this->dialogContentX + local_f8 + leftPosition - this->helpContentScrollX, - this->dialogContentY - this->helpContentScrollOffsetY + lineY - - this->helpContentScrollY, - iVar5 - this->dialogContentX + local_f8 + leftPosition, - currentFontLineHeight + 2)) { - if (local_12c) { - this->field49_0x23964 = local_114 + local_118; - this->field50_0x23968 = currentLinkId; - } else { - this->field49_0x23964 = local_114; - } + lineY += currentFontLineHeight + 1; + if (this->useAlternateHelpTab && param_1 == 1) { + local_100 = local_11c; + local_11c = local_114 + i; + ++local_134; + if (0 < this->field51_0x2396c && 2 <= local_134) { + local_134 = -10000; + this->activeHelpHotspotIndex = local_100 + local_10c; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } + this->field51_0x2396c = 0; } - } else { - lineEndY = lineY + currentFontLineHeight; - lineStartY = lineY; - if (param_1 == 1) { - if (local_12c) { - local_10c = (local_118 - local_11c) + local_114; - if (this->field51_0x2396c < 0) { - this->activeHelpHotspotIndex = DAT_00df3348::instance + local_100; - if (this->activeHelpHotspotIndex >= local_11c) { - this->activeHelpHotspotIndex = local_11c - 1; - } - this->field51_0x2396c = 0; - } - local_134 = 0; - MACRO_CALL_MEMBER( - UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( - this->dialogContentX + local_f8 - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + -1 + lineY, - this->dialogContentX + local_f8 - 1 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, - COL_DARK_LIME::instance.shortValue); - MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, - DAT_PencilRenderCore::ptr)(this->dialogContentX + local_f8 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY - 1 + lineY, - this->dialogContentX + local_f8 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + 1 + lineEndY, - COL_DARK_LIME::instance.shortValue); - local_e4 = TRUE; - } - iVar5 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( - textMemUnion.text[local_118], this->dialogContentX + local_f8 + leftPosition, - this->dialogContentY - this->helpContentScrollOffsetY + lineY, charColor, 0); - local_f0 = TRUE; - if (MACRO_CALL_MEMBER( - Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( - this->dialogContentX + local_f8 + leftPosition - this->helpContentScrollX, - this->dialogContentY - this->helpContentScrollOffsetY + lineY - - this->helpContentScrollY, - iVar5 - this->dialogContentX + local_f8 + leftPosition, - currentFontLineHeight + 2)) { - if (local_12c) { - this->field49_0x23964 = local_114 + local_118; - this->field50_0x23968 = currentLinkId; - } else { - this->field49_0x23964 = local_114; + } + do { + leftPosition = this->lineLayoutTable[++lineY].leftBorder; + } while (leftPosition == -1); + if (centerCurrentLine) { + local_f8 = this->lineLayoutTable[lineY].widthForCentering / 2; + } + } + if (this->useAlternateHelpTab && local_114 + i == this->activeHelpHotspotIndex) { + lineStartY = lineY; + lineEndY = lineY + currentFontLineHeight; + if (param_1 == 1) { + if (local_12c) { + local_10c = (i - local_11c) + local_114; + if (this->field51_0x2396c < 0) { + this->activeHelpHotspotIndex = DAT_00df3348::instance + local_100; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } + this->field51_0x2396c = 0; } + local_134 = 0; + int xPos = this->dialogContentX + local_f8; + int yPos = this->dialogContentY - this->helpContentScrollOffsetY; + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, + DAT_PencilRenderCore::ptr)(xPos - 1 + leftPosition, yPos - 1 + lineY, + xPos - 1 + leftPosition, yPos + 1 + lineEndY, + COL_DARK_LIME::instance.shortValue); + xPos = this->dialogContentX + local_f8; + yPos = this->dialogContentY - this->helpContentScrollOffsetY; + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, + DAT_PencilRenderCore::ptr)(xPos + leftPosition, yPos - 1 + lineY, + xPos + leftPosition, yPos + 1 + lineEndY, COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; } } - leftPosition += wideCharWidth; } - continue; - } - } - iVar5 = this->dialogContentX + leftPosition; - local_104 = (this->dialogContentY - this->helpContentScrollOffsetY) + lineY; - if (local_120) { - iVar5 += this->lineLayoutTable[lineY].unknown2 / 2; - } - int const wideStrLength = wcslen((wchar_t*)pwVar6); - for (int i = 0; i < wideStrLength; ++i) { - local_f8 = local_114 - local_11c; - if ((this->useAlternateHelpTab == 0) || (i + local_114 != this->activeHelpHotspotIndex)) { if (param_1 == 1) { + int charXPos = this->dialogContentX + local_f8 + leftPosition; + int charYPos = this->dialogContentY - this->helpContentScrollOffsetY + lineY; + + wchar_t currentChar = textToRender.text[i]; + int const newCharXPos = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, + currentFontClass)(currentChar, charXPos, charYPos, charColor, 0); local_f0 = TRUE; - iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( - textMemUnion.text[i], iVar5, local_104, charColor, 0); if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( - iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, - iVar12 - iVar5, currentFontLineHeight + 2)) { + charXPos - this->helpContentScrollX, charYPos - this->helpContentScrollY, + newCharXPos - charXPos, currentFontLineHeight + 2)) { if (local_12c) { - this->field49_0x23964 = i + local_114; - this->field50_0x23968 = currentLinkId; + this->field49_0x23964 = local_114 + i; + this->currentLinkId = currentLinkId; } else { this->field49_0x23964 = local_114; } } - } else { - dVar14 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( - textMemUnion.text[i]); - iVar12 = iVar5 + dVar14; - } - } else { - if (param_1 == 1 && local_12c) { - MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, - DAT_PencilRenderCore::ptr)(iVar5 + -1, local_104 - 1, iVar5 + -1, - local_104 + 1 + currentFontLineHeight, COL_DARK_LIME::instance.shortValue); - MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, - DAT_PencilRenderCore::ptr)(iVar5, local_104 - 1, iVar5, - local_104 + 1 + currentFontLineHeight, COL_DARK_LIME::instance.shortValue); - local_e4 = TRUE; } - lineEndY = lineY + currentFontLineHeight; - lineStartY = lineY; - if (param_1 == 1) { - local_10c = local_f8 + i; - local_134 = 0; - if (this->field51_0x2396c < 0 && local_12c) { - this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; - if (this->activeHelpHotspotIndex >= local_11c) { - this->activeHelpHotspotIndex = local_11c + -1; - } - this->field51_0x2396c = 0; - } - local_f0 = TRUE; - iVar12 = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( - textMemUnion.text[i], iVar5, local_104, charColor, 0); - if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( - iVar5 - this->helpContentScrollX, local_104 - this->helpContentScrollY, - iVar12 - iVar5, currentFontLineHeight + 2)) { - if (local_12c) { - this->field49_0x23964 = i + local_114; - this->field50_0x23968 = currentLinkId; - } else { - this->field49_0x23964 = local_114; - } + + leftPosition += wideCharWidth; + } + continue; + } + } + int charXPos = this->dialogContentX + leftPosition; + int charYPos = (this->dialogContentY - this->helpContentScrollOffsetY) + lineY; + if (centerCurrentLine) { + charXPos += this->lineLayoutTable[lineY].widthForCentering / 2; + } + int wordLength = wcslen(textToRender.text); + for (int i = 0; i < wordLength; ++i) { + if (this->useAlternateHelpTab && i + local_114 == this->activeHelpHotspotIndex) { + if (param_1 == 1 && local_12c) { + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + charXPos - 1, charYPos - 1, charXPos - 1, charYPos + 1 + currentFontLineHeight, + COL_DARK_LIME::instance.shortValue); + MACRO_CALL_MEMBER(UI::Rendering::PencilRenderCore_Func::drawLine, DAT_PencilRenderCore::ptr)( + charXPos, charYPos - 1, charXPos, charYPos + 1 + currentFontLineHeight, + COL_DARK_LIME::instance.shortValue); + local_e4 = TRUE; + } + lineStartY = lineY; + lineEndY = lineY + currentFontLineHeight; + if (param_1 == 1) { + local_134 = 0; + local_10c = local_114 - local_11c + i; + if (this->field51_0x2396c < 0 && local_12c) { + this->activeHelpHotspotIndex = local_100 + DAT_00df3348::instance; + if (this->activeHelpHotspotIndex >= local_11c) { + this->activeHelpHotspotIndex = local_11c - 1; } + this->field51_0x2396c = 0; + } + } + } + + if (param_1 == 1) { + local_f0 = TRUE; + int oldCharPos = charXPos; + wchar_t const currentChar = textToRender.text[i]; + charXPos = MACRO_CALL_MEMBER(FontSizeClass_Func::renderWideChar, currentFontClass)( + currentChar, charXPos, charYPos, charColor, 0); + if (MACRO_CALL_MEMBER(Input::MouseState_Func::isMouseInsideBox, DAT_MouseState::ptr)( + oldCharPos - this->helpContentScrollX, charYPos - this->helpContentScrollY, + charXPos - oldCharPos, currentFontLineHeight + 2)) { + if (local_12c) { + this->field49_0x23964 = i + local_114; + this->currentLinkId = currentLinkId; } else { - dVar14 = MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( - textMemUnion.text[i]); - iVar12 = iVar5 + dVar14; + this->field49_0x23964 = local_114; } } - iVar5 = iVar12; + } else { + charXPos += MACRO_CALL_MEMBER(FontSizeClass_Func::getWideCharWidth, currentFontClass)( + textToRender.text[i]); } - leftPosition = local_f4; } - } + leftPosition += textWidth; + } while (!abortProcessing); + return FALSE; } - } } diff --git a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp index fee866c9d8..08998118cb 100644 --- a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp +++ b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp @@ -16,7 +16,7 @@ namespace Text { void TextEditorState::renderHelpImageHotspots() { for (int i = 0; i < this->imageHotspotCount; ++i) { - int _gfxIndex = 99 - this->imageHotspotTable[i].imageRelated; + int _gfxIndex = 99 - this->imageHotspotTable[i].imageIndex; if ((this->useInGameHelpHandler || this->helpDialogVariant == 1) && !MACRO_CALL_MEMBER(UI::Rendering::TextureRenderCore_Func::checkIfGfxTgxStartsWithTransparentPixels, DAT_TextureRenderCoreObject::ptr)(_gfxIndex)) { @@ -64,7 +64,7 @@ namespace Text { this->imageHotspotTable[i].yPos - this->helpContentScrollY + this->dialogContentY - this->helpContentScrollOffsetY, boxWidth, boxHeight)) { - this->field50_0x23968 = this->imageHotspotTable[i].unknown3; + this->currentLinkId = this->imageHotspotTable[i].linkId; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 91ba63d60a..422a04fb7a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18759,7 +18759,7 @@ SHC_3BB0A8C1_0x0045F580 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F5B0 | 99.0% | Reimplemented, two cases where an "edx + ecx" is flipped to "ecx + edx" -SHC_3BB0A8C1_0x0045FDC0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045FDC0 | 70.1% | Reimplemented, but heavy structural mismatch, seems functional SHC_3BB0A8C1_0x0045FEC0 | 0.0% | Pending From d799d92df507805c04b5dea0b8c1d25c722cb622 Mon Sep 17 00:00:00 2001 From: TheRedDaemon <66257843+TheRedDaemon@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:16:01 +0200 Subject: [PATCH 44/44] reimplement: OpenSHC::Text::TextEditorState clean up --- src/OpenSHC/OS.func.hpp | 8 -------- src/OpenSHC/OS.hpp | 4 ---- src/OpenSHC/Text/TextEditorState/parseHlp.cpp | 11 +++++++---- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/OS.func.hpp b/src/OpenSHC/OS.func.hpp index 1be1b6d1ee..4523a08354 100644 --- a/src/OpenSHC/OS.func.hpp +++ b/src/OpenSHC/OS.func.hpp @@ -179,13 +179,5 @@ namespace OS_Func { void(__cdecl*)(int _Code), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00583D55, &OpenSHC::OS::_exit) _exit; - MACRO_FUNCTION_RESOLVER(int(__cdecl*)(FILE*, wchar_t const*, ...), REIMPLEMENTED_CRT, - Address::SHC_3BB0A8C1_0x005807A8, &OpenSHC::OS::_fwprintf) - _fwprintf; - - MACRO_FUNCTION_RESOLVER( - long(__cdecl*)(wchar_t const*), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00580C0B, &OpenSHC::OS::__wtol) - __wtol; - } // namespace OS_Func } // namespace OpenSHC diff --git a/src/OpenSHC/OS.hpp b/src/OpenSHC/OS.hpp index de952d1600..b0cad4b807 100644 --- a/src/OpenSHC/OS.hpp +++ b/src/OpenSHC/OS.hpp @@ -103,9 +103,5 @@ namespace OS { void __cdecl _exit(int _Code); - int _fwprintf(FILE* stream, wchar_t const* format, ...); - - long __wtol(wchar_t const* str); - } // namespace OS } // namespace OpenSHC diff --git a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp index cfc8eb8fb3..42a2a910a8 100644 --- a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp +++ b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp @@ -5,8 +5,8 @@ #include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" #include "OpenSHC/Util/WideCharMultiByteState.func.hpp" #include "OpenSHC/Text/Enums/HelpTextPicturePositionToken.hpp" -#include "OpenSHC/wstring-literals.hpp" #include "OpenSHC/string-literals.hpp" +#include "OpenSHC/wstring-literals.hpp" #include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" #include "OpenSHC/Globals/DAT_TextEditorState.hpp" @@ -117,13 +117,16 @@ namespace Text { if (!MACRO_CALL(OS_Func::__wcsicmp)(u_left_005a5714, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTPPT_LEFT; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_right_005a5708, picPosition)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)( + u_right_005a5708, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTPPT_RIGHT; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_centre_005a56f8, picPosition)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)( + u_centre_005a56f8, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTPPT_CENTRE; - } else if (!MACRO_CALL(OS_Func::__wcsicmp)(u_here_005a56ec, picPosition)) { + } else if (!MACRO_CALL(OS_Func::__wcsicmp)( + u_here_005a56ec, picPosition)) { this->DAT_PointerToTemporaryTextMemory[textMemIndex++] = Enums::HTPPT_HERE; }