From 1390bbc14412ea0dc678cbfd785fe7c4208e4b2e 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/41] reimplement: SHC_3BB0A8C1_0x0045F130 100% --- src/OpenSHC/Text/TextEditorState.hpp | 9 +++- .../Constructor_TextEditorState.cpp | 42 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 3d08c6d0..bd21f316 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -58,7 +58,7 @@ namespace Text { char* customHelpTextPointer; // 0x000000F4 length: 4 undefined4 isCustomHelpTextWide; // 0x000000F8 length: 4 undefined4 customHelpTextBufferSize; // 0x000000FC length: 4 - undefined4 customTextMaxLength; // 0x00000100 length: 4 + int customTextMaxLength; // 0x00000100 length: 4 char soundFileNames[5][1000]; // 0x00000104 length: 5000 byte soundFilePlayedFlags[5]; // 0x0000148C length: 5 undefined1 padding_0x1491[3]; // 0x00001491 length: 3 @@ -68,7 +68,12 @@ namespace Text { short lineLayoutTable[60000]; // 0x000062BC length: 120000 int imageHotspotCount; // 0x0002377C length: 4 short imageHotspotTable[50][4]; // 0x00023780 length: 400 - int intArray1[25]; // 0x00023910 length: 100 + int intArray1[20]; // 0x00023910 length: 80 + int unknown_0x23960; // 0x00023960 length: 4 + int unknown_0x23964; // 0x00023964 length: 4 + int unknown_0x23968; // 0x00023968 length: 4 + int unknown_0x2396C; // 0x0002396C length: 4 + int unknown_0x23970; // 0x00023970 length: 4 private: TextEditorState(TextEditorState const&); diff --git a/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp b/src/OpenSHC/Text/TextEditorState/Constructor_TextEditorState.cpp new file mode 100644 index 00000000..70d1b72d --- /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 10a0c2b0..1cdce1a2 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 | 0.0% | Pending -SHC_3BB0A8C1_0x0045F130 | 0.0% | Pending +SHC_3BB0A8C1_0x0045F130 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045F240 | 0.0% | Pending From c9ba4ded4e1f53059cc68d4925f506e09d743e58 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/41] reimplement: SHC_3BB0A8C1_0x0045D080 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../Text/TextEditorState/setHelpWindowBounds.cpp | 16 ++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index bd21f316..4723b9d1 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -86,7 +86,7 @@ namespace Text { // Constructor TextEditorState* Constructor_TextEditorState(); - void setHelpWindowBounds(undefined4 param_1, undefined4 param_2, undefined4 param_3, undefined4 param_4); + void setHelpWindowBounds(undefined4 x, undefined4 y, undefined4 height, undefined4 width); void resetHelpStateFields(); diff --git a/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp b/src/OpenSHC/Text/TextEditorState/setHelpWindowBounds.cpp new file mode 100644 index 00000000..ba116919 --- /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 1cdce1a2..2e8a6481 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 | 0.0% | Pending -SHC_3BB0A8C1_0x0045D080 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D080 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D0B0 | 0.0% | Pending From f3593be0845bd338d1ec81e39d3d4e697526e3c8 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/41] 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 00000000..de0e1f34 --- /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 2e8a6481..73515fbb 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 | 0.0% | Pending -SHC_3BB0A8C1_0x0045D0C0 | 0.0% | Pending +SHC_3BB0A8C1_0x0045D0C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0045D140 | 0.0% | Pending From aed0b629a6c4237107edf4af92e09b8c9dd2b914 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/41] reimplement: SHC_3BB0A8C1_0x0045D140 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../findHelpSectionIndexByName.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 4723b9d1..660c4d90 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -35,7 +35,7 @@ namespace Text { BOOLEnum helpSectionParseSucceeded; // 0x00000024 length: 4 int currentHelpSectionID; // 0x00000028 length: 4 int helpSectionHistoryStack[30]; // 0x0000002C length: 120 - undefined4 counter; // 0x000000A4 length: 4 + int counter; // 0x000000A4 length: 4 undefined4 helpContentScrollOffsetY; // 0x000000A8 length: 4 undefined4 topVisibleLineIndex; // 0x000000AC length: 4 undefined4 dialogX; // 0x000000B0 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp b/src/OpenSHC/Text/TextEditorState/findHelpSectionIndexByName.cpp new file mode 100644 index 00000000..018ef45a --- /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 73515fbb..c0bfaaad 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18153,7 +18153,7 @@ SHC_3BB0A8C1_0x0045D0B0 | 0.0% | Pending 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 ee21369525af4ffa1f75ef2b8f3928666d1b03c1 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/41] 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 70d1b72d..afb18c1b 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 00000000..d1be3a1e --- /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 c0bfaaad..b6352b78 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 93f462042f67fd6162d796fe00638c43971822a5 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/41] reimplement: SHC_3BB0A8C1_0x0045D200 100% --- IMPLEMENTATION_CHEAT_SHEET.md | 2 + src/OpenSHC/Text/TextEditorState.func.hpp | 4 +- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../Text/TextEditorState/parseHLPPart.cpp | 78 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 5 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 0b7151e3..5d7dac4f 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -196,6 +196,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. + ### GOTO A function may contain multiple GOTOs. diff --git a/src/OpenSHC/Text/TextEditorState.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index d8f348f7..6d3169a3 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -35,8 +35,8 @@ namespace Text { &TextEditorState::findOrAddHelpSectionName) findOrAddHelpSectionName; - MACRO_FUNCTION_RESOLVER( - uint (TextEditorState::*)(FILE*), false, Address::SHC_3BB0A8C1_0x0045D200, &TextEditorState::parseHLPPart) + MACRO_FUNCTION_RESOLVER(LPCWSTR (TextEditorState::*)(FILE*), false, Address::SHC_3BB0A8C1_0x0045D200, + &TextEditorState::parseHLPPart) parseHLPPart; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(), false, Address::SHC_3BB0A8C1_0x0045D370, diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 660c4d90..76c417cc 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -94,7 +94,7 @@ namespace Text { int findOrAddHelpSectionName(char* param_1); - uint parseHLPPart(FILE* filePointer); + LPCWSTR parseHLPPart(FILE* filePointer); void loadHelpSectionGraphics(); diff --git a/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp b/src/OpenSHC/Text/TextEditorState/parseHLPPart.cpp new file mode 100644 index 00000000..f630aa3b --- /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 b6352b78..0c9e4dc0 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 2082ac1f8401ece7c9126ec9277d3e1fe6073bf3 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/41] reimplement: SHC_3BB0A8C1_0x0045D370 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../loadHelpSectionGraphics.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 76c417cc..9428f0fe 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -64,7 +64,7 @@ namespace Text { undefined1 padding_0x1491[3]; // 0x00001491 length: 3 undefined4 soundFileCount; // 0x00001494 length: 4 char graphicFileNames[20][1000]; // 0x00001498 length: 20000 - undefined4 graphicFileCount; // 0x000062B8 length: 4 + int graphicFileCount; // 0x000062B8 length: 4 short lineLayoutTable[60000]; // 0x000062BC length: 120000 int imageHotspotCount; // 0x0002377C length: 4 short imageHotspotTable[50][4]; // 0x00023780 length: 400 diff --git a/src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp b/src/OpenSHC/Text/TextEditorState/loadHelpSectionGraphics.cpp new file mode 100644 index 00000000..ea5ba6b5 --- /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 0c9e4dc0..9393da1c 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 9fb6002d72b468e586e4a6648e36ce25743f67bf 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/41] reimplement: SHC_3BB0A8C1_0x0045D3C0 100% --- src/OpenSHC/Text/TextEditorState.func.hpp | 10 +++--- src/OpenSHC/Text/TextEditorState.hpp | 6 ++-- .../getWideCharOrWideCharPointer.cpp | 36 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 4 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp diff --git a/src/OpenSHC/Text/TextEditorState.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index 6d3169a3..74e45c7a 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -35,17 +35,17 @@ namespace Text { &TextEditorState::findOrAddHelpSectionName) findOrAddHelpSectionName; - MACRO_FUNCTION_RESOLVER(LPCWSTR (TextEditorState::*)(FILE*), false, Address::SHC_3BB0A8C1_0x0045D200, - &TextEditorState::parseHLPPart) + MACRO_FUNCTION_RESOLVER( + LPWSTR (TextEditorState::*)(FILE*), false, Address::SHC_3BB0A8C1_0x0045D200, &TextEditorState::parseHLPPart) parseHLPPart; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(), false, Address::SHC_3BB0A8C1_0x0045D370, &TextEditorState::loadHelpSectionGraphics) loadHelpSectionGraphics; - MACRO_FUNCTION_RESOLVER(undefined* (TextEditorState::*)(int*), false, Address::SHC_3BB0A8C1_0x0045D3C0, - &TextEditorState::getWideCharPointer) - getWideCharPointer; + MACRO_FUNCTION_RESOLVER(uint (TextEditorState::*)(int*), false, Address::SHC_3BB0A8C1_0x0045D3C0, + &TextEditorState::getWideCharOrWideCharPointer) + getWideCharOrWideCharPointer; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(), false, Address::SHC_3BB0A8C1_0x0045D430, &TextEditorState::renderHelpImageHotspots) diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 9428f0fe..c2c5022a 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -23,7 +23,7 @@ namespace Text { // SIZE: 0x00023974 class TextEditorState { public: - pointer DAT_PointerToTemporaryTextMemory; // 0x00000000 length: 4 + LPWSTR DAT_PointerToTemporaryTextMemory; // 0x00000000 length: 4 undefined4 customHelpTextLength; // 0x00000004 length: 4 undefined4 isDialogStateInitialized; // 0x00000008 length: 4 undefined4 helpDialogVariant; // 0x0000000C length: 4 @@ -94,11 +94,11 @@ namespace Text { int findOrAddHelpSectionName(char* param_1); - LPCWSTR parseHLPPart(FILE* filePointer); + LPWSTR parseHLPPart(FILE* filePointer); void loadHelpSectionGraphics(); - undefined* getWideCharPointer(int* param_1); + uint getWideCharOrWideCharPointer(int* param_1); void renderHelpImageHotspots(); diff --git a/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp b/src/OpenSHC/Text/TextEditorState/getWideCharOrWideCharPointer.cpp new file mode 100644 index 00000000..7e28eded --- /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 9393da1c..82eea066 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 39376c9113c11055c426c8e072fb95fd573112fe 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/41] reimplement: SHC_3BB0A8C1_0x0045D430 100% --- src/OpenSHC/Text/TextEditorState.hpp | 16 +++- .../renderHelpImageHotspots.cpp | 73 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index c2c5022a..e2f5770f 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -16,6 +16,14 @@ namespace OpenSHC { namespace Text { + // TODO: Needs proper place (and name?) + struct ImageHotspot { + short xPos; + short yPos; + short imageRelated; + short unknown3; + }; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; #pragma pack(push, 1) @@ -42,10 +50,10 @@ namespace Text { undefined4 dialogY; // 0x000000B4 length: 4 undefined4 dialogWidth; // 0x000000B8 length: 4 undefined4 dialogHeight; // 0x000000BC length: 4 - undefined4 dialogContentX; // 0x000000C0 length: 4 - undefined4 dialogContentY; // 0x000000C4 length: 4 + int dialogContentX; // 0x000000C0 length: 4 + int dialogContentY; // 0x000000C4 length: 4 undefined4 dialogContentHeight; // 0x000000C8 length: 4 - undefined4 dialogContentWidth; // 0x000000CC length: 4 + int dialogContentWidth; // 0x000000CC length: 4 undefined4 helpContentScrollX; // 0x000000D0 length: 4 undefined4 helpContentScrollY; // 0x000000D4 length: 4 undefined4 activeHelpHotspotIndex; // 0x000000D8 length: 4 @@ -67,7 +75,7 @@ namespace Text { int graphicFileCount; // 0x000062B8 length: 4 short lineLayoutTable[60000]; // 0x000062BC length: 120000 int imageHotspotCount; // 0x0002377C length: 4 - short imageHotspotTable[50][4]; // 0x00023780 length: 400 + ImageHotspot imageHotspotTable[50]; // 0x00023780 length: 400 int intArray1[20]; // 0x00023910 length: 80 int unknown_0x23960; // 0x00023960 length: 4 int unknown_0x23964; // 0x00023964 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp b/src/OpenSHC/Text/TextEditorState/renderHelpImageHotspots.cpp new file mode 100644 index 00000000..d468a9d7 --- /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 82eea066..7e1a4aaa 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 07a1257e67a58913670561607e9dd047d14ab67b 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/41] reimplement: SHC_3BB0A8C1_0x0045D690 100% --- src/OpenSHC/Text/TextEditorState.hpp | 4 ++- .../bltTextToScreenIfNeedBe.cpp | 27 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index e2f5770f..ee256ff3 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -8,6 +8,7 @@ #pragma once +#include "OpenSHC/UI/Enums/MenuViewTypeInt.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "mbstring.h" @@ -24,6 +25,7 @@ namespace Text { short unknown3; }; + using OpenSHC::UI::Enums::MenuViewTypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; #pragma pack(push, 1) @@ -36,7 +38,7 @@ namespace Text { undefined4 isDialogStateInitialized; // 0x00000008 length: 4 undefined4 helpDialogVariant; // 0x0000000C length: 4 undefined4 useInGameHelpHandler; // 0x00000010 length: 4 - undefined4 savedMenuViewType; // 0x00000014 length: 4 + MenuViewTypeInt savedMenuViewType; // 0x00000014 length: 4 undefined4 savedActiveMenuTab; // 0x00000018 length: 4 undefined4 savedMenuFlag; // 0x0000001C length: 4 BOOLEnum pendingCreditsFadeBorder; // 0x00000020 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp b/src/OpenSHC/Text/TextEditorState/bltTextToScreenIfNeedBe.cpp new file mode 100644 index 00000000..d6bb78b8 --- /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 7e1a4aaa..0e3e8ccf 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 3e85a757cf9c46c6f3f84a824db0077a10288ddd 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/41] reimplement: SHC_3BB0A8C1_0x0045D6C0 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/drawBorderStyle0x20.cpp | 37 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index ee256ff3..3b5336ac 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -114,7 +114,7 @@ namespace Text { void bltTextToScreenIfNeedBe(); - void drawBorderStyle0x20(int param_1, int param_2, int param_3, int param_4); + void drawBorderStyle0x20(int dialogX, int dialogY, int dialogWidth, int dialogHeight); void drawHelpWindowBackground(); diff --git a/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp b/src/OpenSHC/Text/TextEditorState/drawBorderStyle0x20.cpp new file mode 100644 index 00000000..c36e3e66 --- /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 0e3e8ccf..8cce50f2 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 31b7b37c6d89c4560749ba7cd09bbe941a972906 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/41] 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 f630aa3b..cc97503d 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 0b45beb95e89930cb4e9224d9ac070f5b6293218 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/41] 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 00000000..ac5555d6 --- /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 8cce50f2..827ec910 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 c323912e07842e9a7e61d77b53c5d6336af50453 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/41] 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 00000000..76afd0b0 --- /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 827ec910..868ec14d 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 fedc863791515b31b19eb8b632045bf600de1225 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/41] 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 00000000..4e668a43 --- /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 868ec14d..755e7a73 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 7c729b51a28aee515ea34d0cf26ac13e8419fd2b 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/41] 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 00000000..dd1e12b3 --- /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 755e7a73..2db0fb48 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 c6780400de767fb0cc03f570f4dfae626b854b97 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/41] 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 00000000..4e5d3ba8 --- /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 2db0fb48..66ce98cf 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 2522f42ceb229350c73cb24d1f02bcc4db5783e1 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/41] 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 00000000..a0c88560 --- /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 66ce98cf..ba3b0714 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 425de6a32cc016b6a61006db7cbf25efef3702f0 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/41] 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 00000000..98ad9021 --- /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 ba3b0714..a88698d2 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 eae57c3049827cd4166a35b204a193e34d80059b 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/41] 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 00000000..d3f15557 --- /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 a88698d2..539629f2 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 c0fead71d0dd20912586fa520cd65a0632bed5f0 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/41] reimplement: SHC_3BB0A8C1_0x0045DA80 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/findSoundIndexByName.cpp | 20 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 3b5336ac..5e7a896e 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -72,7 +72,7 @@ namespace Text { char soundFileNames[5][1000]; // 0x00000104 length: 5000 byte soundFilePlayedFlags[5]; // 0x0000148C length: 5 undefined1 padding_0x1491[3]; // 0x00001491 length: 3 - undefined4 soundFileCount; // 0x00001494 length: 4 + int soundFileCount; // 0x00001494 length: 4 char graphicFileNames[20][1000]; // 0x00001498 length: 20000 int graphicFileCount; // 0x000062B8 length: 4 short lineLayoutTable[60000]; // 0x000062BC length: 120000 diff --git a/src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp b/src/OpenSHC/Text/TextEditorState/findSoundIndexByName.cpp new file mode 100644 index 00000000..f105e1de --- /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 539629f2..cdda4f3a 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 4315629f138a3fdae7e9a407c0bb8d666bae24f2 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/41] 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 00000000..154d8464 --- /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 cdda4f3a..addecbf7 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 831ed4bef66267b71f425091c97e683306c2316a 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/41] reimplement: SHC_3BB0A8C1_0x0045DB40 100% --- src/OpenSHC/OS.func.hpp | 4 + src/OpenSHC/OS.hpp | 2 + src/OpenSHC/OS/OS.cpp | 11 ++ src/OpenSHC/Text/TextEditorState.func.hpp | 8 +- src/OpenSHC/Text/TextEditorState.hpp | 29 ++++- .../saveHelpFileToResource.cpp | 118 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 7 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp diff --git a/src/OpenSHC/OS.func.hpp b/src/OpenSHC/OS.func.hpp index 5527dd60..ced39c6b 100644 --- a/src/OpenSHC/OS.func.hpp +++ b/src/OpenSHC/OS.func.hpp @@ -171,5 +171,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 8f22f3e9..1d9e6887 100644 --- a/src/OpenSHC/OS.hpp +++ b/src/OpenSHC/OS.hpp @@ -99,5 +99,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 05797263..bc455be2 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.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index 74e45c7a..de8f64f7 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -104,12 +104,12 @@ namespace Text { saveHelpFileToResource; MACRO_FUNCTION_RESOLVER(undefined4 (TextEditorState::*)(undefined4), false, Address::SHC_3BB0A8C1_0x0045F080, - &TextEditorState::getHelpTokenAdvanceLength) - getHelpTokenAdvanceLength; + &TextEditorState::helpToken_getHelpTokenAdvanceLength) + helpToken_getHelpTokenAdvanceLength; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(undefined4), false, Address::SHC_3BB0A8C1_0x0045F0D0, - &TextEditorState::insertHelpTextToken) - insertHelpTextToken; + &TextEditorState::helpToken_insertHelpTextToken) + helpToken_insertHelpTextToken; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(), false, Address::SHC_3BB0A8C1_0x0045F240, &TextEditorState::closeHelpDialogAndReturnToMenu) diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 5e7a896e..be2086c9 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -17,7 +17,30 @@ namespace OpenSHC { namespace Text { - // TODO: Needs proper place (and name?) + // TODO: Need proper places (and name?) + + enum HelpTextToken { + HTT_PIC = 1, + HTT_FONT = 2, + HTT_COLOUR = 3, + HTT_LINK = 4, + HTT_ENDLINK = 5, + HTT_NEWPARAGRAPH = 6, + HTT_CENTRE = 7, + HTT_ENDCENTRE = 8, + HTT_LINKCOLOUR = 10, + HTT_SOUND = 11, + HTT_STRING = 12, + HTT_INCLUDE = 14, + }; + + enum HelpTextPicturePositionToken { + HTT_PIC_LEFT = 0, + HTT_PIC_CENTRE = 1, + HTT_PIC_RIGHT = 2, + HTT_PIC_HERE = 3, + }; + struct ImageHotspot { short xPos; short yPos; @@ -138,9 +161,9 @@ namespace Text { void saveHelpFileToResource(); - undefined4 getHelpTokenAdvanceLength(undefined4 param_1); + undefined4 helpToken_getHelpTokenAdvanceLength(undefined4 param_1); - void insertHelpTextToken(undefined4 param_1); + void helpToken_insertHelpTextToken(undefined4 param_1); void closeHelpDialogAndReturnToMenu(); diff --git a/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp b/src/OpenSHC/Text/TextEditorState/saveHelpFileToResource.cpp new file mode 100644 index 00000000..1ae12edc --- /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 addecbf7..2f7dfcf8 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 d64f00e42aa9daedacbfbd8ee8ab2a9abb7739a4 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/41] reimplement: SHC_3BB0A8C1_0x0045F080 and SHC_3BB0A8C1_0x0045F0D0 100% --- src/OpenSHC/Text/TextEditorState.func.hpp | 8 ++-- src/OpenSHC/Text/TextEditorState.hpp | 8 ++-- .../Text/TextEditorState/helpToken.cpp | 39 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 4 +- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/helpToken.cpp diff --git a/src/OpenSHC/Text/TextEditorState.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index de8f64f7..3f62c46c 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -103,13 +103,13 @@ namespace Text { &TextEditorState::saveHelpFileToResource) saveHelpFileToResource; - MACRO_FUNCTION_RESOLVER(undefined4 (TextEditorState::*)(undefined4), false, Address::SHC_3BB0A8C1_0x0045F080, + MACRO_FUNCTION_RESOLVER(int (TextEditorState::*)(HelpTextToken), false, Address::SHC_3BB0A8C1_0x0045F080, &TextEditorState::helpToken_getHelpTokenAdvanceLength) helpToken_getHelpTokenAdvanceLength; - MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(undefined4), false, Address::SHC_3BB0A8C1_0x0045F0D0, - &TextEditorState::helpToken_insertHelpTextToken) - helpToken_insertHelpTextToken; + MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(HelpTextToken), false, Address::SHC_3BB0A8C1_0x0045F0D0, + &TextEditorState::helpToken_insertSpaceForHelpTextToken) + helpToken_insertSpaceForHelpTextToken; MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(), false, Address::SHC_3BB0A8C1_0x0045F240, &TextEditorState::closeHelpDialogAndReturnToMenu) diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index be2086c9..f7b7eab0 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -57,7 +57,7 @@ namespace Text { class TextEditorState { public: LPWSTR DAT_PointerToTemporaryTextMemory; // 0x00000000 length: 4 - undefined4 customHelpTextLength; // 0x00000004 length: 4 + int customHelpTextLength; // 0x00000004 length: 4 undefined4 isDialogStateInitialized; // 0x00000008 length: 4 undefined4 helpDialogVariant; // 0x0000000C length: 4 undefined4 useInGameHelpHandler; // 0x00000010 length: 4 @@ -81,7 +81,7 @@ namespace Text { int dialogContentWidth; // 0x000000CC length: 4 undefined4 helpContentScrollX; // 0x000000D0 length: 4 undefined4 helpContentScrollY; // 0x000000D4 length: 4 - undefined4 activeHelpHotspotIndex; // 0x000000D8 length: 4 + int activeHelpHotspotIndex; // 0x000000D8 length: 4 undefined4 helpDialogSubMode; // 0x000000DC length: 4 undefined4 useAlternateHelpTab; // 0x000000E0 length: 4 undefined4 isCustomTextMode; // 0x000000E4 length: 4 @@ -161,9 +161,9 @@ namespace Text { void saveHelpFileToResource(); - undefined4 helpToken_getHelpTokenAdvanceLength(undefined4 param_1); + int helpToken_getHelpTokenAdvanceLength(HelpTextToken token); - void helpToken_insertHelpTextToken(undefined4 param_1); + void helpToken_insertSpaceForHelpTextToken(HelpTextToken token); void closeHelpDialogAndReturnToMenu(); diff --git a/src/OpenSHC/Text/TextEditorState/helpToken.cpp b/src/OpenSHC/Text/TextEditorState/helpToken.cpp new file mode 100644 index 00000000..6931a374 --- /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 2f7dfcf8..b9eef184 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 | 0.0% | Pending From 52fa088ab835ea3a4853b4d06107e02936e5590b 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/41] 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 00000000..04a89a42 --- /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 b9eef184..056a7bad 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -18751,7 +18751,7 @@ SHC_3BB0A8C1_0x0045F120 | 0.0% | Pending 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 d78e1f5beafa7efa100e3c6d7d033757982f4d8d 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/41] reimplement: SHC_3BB0A8C1_0x0045F470 100% --- src/OpenSHC/Text/TextEditorState.func.hpp | 2 +- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/readCrusaderHelpHlp.cpp | 66 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp diff --git a/src/OpenSHC/Text/TextEditorState.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index 3f62c46c..591c9f26 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -115,7 +115,7 @@ namespace Text { &TextEditorState::closeHelpDialogAndReturnToMenu) closeHelpDialogAndReturnToMenu; - MACRO_FUNCTION_RESOLVER(int (TextEditorState::*)(LPCSTR), false, Address::SHC_3BB0A8C1_0x0045F470, + MACRO_FUNCTION_RESOLVER(FILE* (TextEditorState::*)(LPCSTR), false, Address::SHC_3BB0A8C1_0x0045F470, &TextEditorState::readCrusaderHelpHlp) readCrusaderHelpHlp; diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index f7b7eab0..04ec6548 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -167,7 +167,7 @@ namespace Text { void closeHelpDialogAndReturnToMenu(); - int readCrusaderHelpHlp(LPCSTR param_1); + FILE* readCrusaderHelpHlp(LPCSTR searchedPart); BOOLEnum loadAndParseHelpFile(char const* param_1); diff --git a/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp b/src/OpenSHC/Text/TextEditorState/readCrusaderHelpHlp.cpp new file mode 100644 index 00000000..1f6bf9c8 --- /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 056a7bad..1ec2a83b 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 7fac1762ed2ecba9b2803764d7df38b96862bcb7 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/41] reimplement: SHC_3BB0A8C1_0x0045F580 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/loadAndParseHelpFile.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 04ec6548..e5ee488e 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -169,7 +169,7 @@ namespace Text { FILE* readCrusaderHelpHlp(LPCSTR searchedPart); - BOOLEnum loadAndParseHelpFile(char const* param_1); + BOOLEnum loadAndParseHelpFile(char const* searchedPart); void parseHlp(); diff --git a/src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp b/src/OpenSHC/Text/TextEditorState/loadAndParseHelpFile.cpp new file mode 100644 index 00000000..7a0e6bf8 --- /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 1ec2a83b..884c282c 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 c438107d034fbddb456803978bcb9291648486f3 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/41] 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.hpp | 2 +- src/OpenSHC/Text/TextEditorState/parseHlp.cpp | 352 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 7 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/parseHlp.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 5d7dac4f..ea53f307 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -144,6 +144,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. ### Loops diff --git a/src/OpenSHC/OS.func.hpp b/src/OpenSHC/OS.func.hpp index ced39c6b..c825a2f8 100644 --- a/src/OpenSHC/OS.func.hpp +++ b/src/OpenSHC/OS.func.hpp @@ -175,5 +175,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 1d9e6887..5487c733 100644 --- a/src/OpenSHC/OS.hpp +++ b/src/OpenSHC/OS.hpp @@ -101,5 +101,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 bc455be2..e300ed41 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.hpp b/src/OpenSHC/Text/TextEditorState.hpp index e5ee488e..adcb42fc 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -101,7 +101,7 @@ namespace Text { short lineLayoutTable[60000]; // 0x000062BC length: 120000 int imageHotspotCount; // 0x0002377C length: 4 ImageHotspot imageHotspotTable[50]; // 0x00023780 length: 400 - int intArray1[20]; // 0x00023910 length: 80 + wchar_t* intArray1[20]; // 0x00023910 length: 80 int unknown_0x23960; // 0x00023960 length: 4 int unknown_0x23964; // 0x00023964 length: 4 int unknown_0x23968; // 0x00023968 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/parseHlp.cpp b/src/OpenSHC/Text/TextEditorState/parseHlp.cpp new file mode 100644 index 00000000..792efc70 --- /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 884c282c..730f2bde 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 5a0346d09b9225d01fd62271f07773069dddad32 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/41] reimplement: SHC_3BB0A8C1_0x004614D0 100% --- src/OpenSHC/Text/TextEditorState.hpp | 8 ++++++- .../initializeAndLayoutHelpText.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index adcb42fc..20a768be 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -48,6 +48,12 @@ namespace Text { short unknown3; }; + struct LineLayout { + short unknown0; + short unknown1; + short unknown2; + }; + using OpenSHC::UI::Enums::MenuViewTypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; @@ -98,7 +104,7 @@ namespace Text { int soundFileCount; // 0x00001494 length: 4 char graphicFileNames[20][1000]; // 0x00001498 length: 20000 int graphicFileCount; // 0x000062B8 length: 4 - short lineLayoutTable[60000]; // 0x000062BC length: 120000 + LineLayout lineLayoutTable[20000]; // 0x000062BC length: 120000 int imageHotspotCount; // 0x0002377C length: 4 ImageHotspot imageHotspotTable[50]; // 0x00023780 length: 400 wchar_t* intArray1[20]; // 0x00023910 length: 80 diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp new file mode 100644 index 00000000..44b86a79 --- /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 730f2bde..89e688d9 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 e3e3167a111a79311bd7daebf2692d1c48abf739 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/41] 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 00000000..72ef3128 --- /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 89e688d9..a0592edc 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 2f334d1d9fd38d586b10c88a3f20a8892e4e182d 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/41] 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 00000000..13ff6f4a --- /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 a0592edc..78f4ee7c 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 f1b62c75e6d64bcace78045b9597643386f83cea 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/41] reimplement: SHC_3BB0A8C1_0x004619D0 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../loadAndLayoutHelpContent.cpp | 22 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 20a768be..a00e9ea8 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -76,7 +76,7 @@ namespace Text { int helpSectionHistoryStack[30]; // 0x0000002C length: 120 int counter; // 0x000000A4 length: 4 undefined4 helpContentScrollOffsetY; // 0x000000A8 length: 4 - undefined4 topVisibleLineIndex; // 0x000000AC length: 4 + int topVisibleLineIndex; // 0x000000AC length: 4 undefined4 dialogX; // 0x000000B0 length: 4 undefined4 dialogY; // 0x000000B4 length: 4 undefined4 dialogWidth; // 0x000000B8 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp b/src/OpenSHC/Text/TextEditorState/loadAndLayoutHelpContent.cpp new file mode 100644 index 00000000..62a5eddb --- /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 78f4ee7c..bd9ccfca 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 d474dae72943be24326acafddd3308d5e7cd9351 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/41] reimplement: SHC_3BB0A8C1_0x00461A20 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../openBuildingHelpDialog.cpp | 79 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index a00e9ea8..7cf1095c 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -189,7 +189,7 @@ namespace Text { void loadAndLayoutHelpContent(); - void openBuildingHelpDialog(int param_1); + void openBuildingHelpDialog(int sectionId); void openInGameHelpDialog(int param_1); diff --git a/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openBuildingHelpDialog.cpp new file mode 100644 index 00000000..fd849ca4 --- /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 bd9ccfca..0ccb7db9 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 2fb2060f5dd46eaa290570fd15836dd50eec24b6 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/41] reimplement: SHC_3BB0A8C1_0x00461B90 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/openInGameHelpDialog.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 7cf1095c..ebb4ee6f 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -66,7 +66,7 @@ namespace Text { int customHelpTextLength; // 0x00000004 length: 4 undefined4 isDialogStateInitialized; // 0x00000008 length: 4 undefined4 helpDialogVariant; // 0x0000000C length: 4 - undefined4 useInGameHelpHandler; // 0x00000010 length: 4 + int useInGameHelpHandler; // 0x00000010 length: 4 MenuViewTypeInt savedMenuViewType; // 0x00000014 length: 4 undefined4 savedActiveMenuTab; // 0x00000018 length: 4 undefined4 savedMenuFlag; // 0x0000001C length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openInGameHelpDialog.cpp new file mode 100644 index 00000000..cdb41b1d --- /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 0ccb7db9..d0b79cbe 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 704085527b21cf0133a86fc6f3c3d70a12f98a63 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/41] reimplement: SHC_3BB0A8C1_0x00461CF0 100% --- src/OpenSHC/Text/TextEditorState.hpp | 4 +- .../openScenarioHelpDialog.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index ebb4ee6f..3bcbe66e 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -191,9 +191,9 @@ namespace Text { void openBuildingHelpDialog(int sectionId); - void openInGameHelpDialog(int param_1); + void openInGameHelpDialog(int sectionId); - void openScenarioHelpDialog(int param_1); + void openScenarioHelpDialog(int sectionId); void openCreditsScrollDialog(int param_1); diff --git a/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp b/src/OpenSHC/Text/TextEditorState/openScenarioHelpDialog.cpp new file mode 100644 index 00000000..cbe2b44f --- /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 d0b79cbe..f89e2956 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 f31cff9bac4f8392c09eee46952069c06639715d 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/41] reimplement: SHC_3BB0A8C1_0x00461E50 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../openCreditsScrollDialog.cpp | 73 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index 3bcbe66e..f3346099 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -195,7 +195,7 @@ namespace Text { void openScenarioHelpDialog(int sectionId); - void openCreditsScrollDialog(int param_1); + void openCreditsScrollDialog(int sectionId); void openMapDescriptionEditorDialog(int param_1); diff --git a/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp b/src/OpenSHC/Text/TextEditorState/openCreditsScrollDialog.cpp new file mode 100644 index 00000000..cc8d182e --- /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 f89e2956..1a045ce8 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 541382e701f2d055b5136a9c3a6a07e881a56059 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/41] reimplement: SHC_3BB0A8C1_0x00461F90 100% --- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../openMapDescriptionEditorDialog.cpp | 75 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index f3346099..d62e0347 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -197,7 +197,7 @@ namespace Text { void openCreditsScrollDialog(int sectionId); - void openMapDescriptionEditorDialog(int param_1); + void openMapDescriptionEditorDialog(int sectionId); void setCustomHelpText(char* param_1, undefined4 param_2); diff --git a/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp b/src/OpenSHC/Text/TextEditorState/openMapDescriptionEditorDialog.cpp new file mode 100644 index 00000000..ab6933b0 --- /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 1a045ce8..b944d8ad 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 3a0265575769bf70f16e2f6c8f3a4bfe1afbdfc7 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/41] reimplement: SHC_3BB0A8C1_0x004620F0 100% --- src/OpenSHC/Text/TextEditorState.func.hpp | 2 +- src/OpenSHC/Text/TextEditorState.hpp | 2 +- .../TextEditorState/setCustomHelpText.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp diff --git a/src/OpenSHC/Text/TextEditorState.func.hpp b/src/OpenSHC/Text/TextEditorState.func.hpp index 591c9f26..49876ccb 100644 --- a/src/OpenSHC/Text/TextEditorState.func.hpp +++ b/src/OpenSHC/Text/TextEditorState.func.hpp @@ -167,7 +167,7 @@ namespace Text { &TextEditorState::openMapDescriptionEditorDialog) openMapDescriptionEditorDialog; - MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(char*, undefined4), false, Address::SHC_3BB0A8C1_0x004620F0, + MACRO_FUNCTION_RESOLVER(void (TextEditorState::*)(char*, int), false, Address::SHC_3BB0A8C1_0x004620F0, &TextEditorState::setCustomHelpText) setCustomHelpText; diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index d62e0347..66abcc15 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -199,7 +199,7 @@ namespace Text { void openMapDescriptionEditorDialog(int sectionId); - void setCustomHelpText(char* param_1, undefined4 param_2); + void setCustomHelpText(char* helpText, int bufferSize); void popHelpDialogStack(); diff --git a/src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp b/src/OpenSHC/Text/TextEditorState/setCustomHelpText.cpp new file mode 100644 index 00000000..83c6495a --- /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 b944d8ad..d5e8e59c 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 06d02d0575ac12ac5ce6a152219c1c62a567b319 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/41] 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 00000000..5fd6604c --- /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 d5e8e59c..577d6588 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 f5040f97418777c0387fabd818c406ff14725a55 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/41] 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 66abcc15..d6981280 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -203,7 +203,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 00000000..45951bd8 --- /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 577d6588..1257d83c 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 f4a4a81dc20d615158687a7c75129fa34aa861ac 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/41] reimplement: SHC_3BB0A8C1_0x0045FDC0 buildable, horrible match --- IMPLEMENTATION_CHEAT_SHEET.md | 49 +- src/OpenSHC/Text/FontSizeClass.hpp | 2 +- src/OpenSHC/Text/TextEditorState.hpp | 9 +- .../initializeAndLayoutHelpText.cpp | 7 +- .../processHelpRichTextTokens.cpp | 815 ++++++++++++++++++ 5 files changed, 855 insertions(+), 27 deletions(-) create mode 100644 src/OpenSHC/Text/TextEditorState/processHelpRichTextTokens.cpp diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index ea53f307..ccb173fb 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -265,25 +265,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/FontSizeClass.hpp b/src/OpenSHC/Text/FontSizeClass.hpp index 84cc26de..7f9baeb7 100644 --- a/src/OpenSHC/Text/FontSizeClass.hpp +++ b/src/OpenSHC/Text/FontSizeClass.hpp @@ -35,7 +35,7 @@ namespace Text { int fontStartImageId_0x8; // 0x00000008 length: 4 FontRenderTypeInt renderType_0xc; // 0x0000000C length: 4 int baselineOffset_0x10; // 0x00000010 length: 4 - dword lineHeight_0x14; // 0x00000014 length: 4 + int lineHeight_0x14; // 0x00000014 length: 4 int letterSpacing_0x18; // 0x00000018 length: 4 int whiteSpaceWidth_0x1c; // 0x0000001C length: 4 HGDIOBJ hgdiobj; // 0x00000020 length: 4 diff --git a/src/OpenSHC/Text/TextEditorState.hpp b/src/OpenSHC/Text/TextEditorState.hpp index d6981280..10b7d7d6 100644 --- a/src/OpenSHC/Text/TextEditorState.hpp +++ b/src/OpenSHC/Text/TextEditorState.hpp @@ -28,6 +28,7 @@ namespace Text { HTT_NEWPARAGRAPH = 6, HTT_CENTRE = 7, HTT_ENDCENTRE = 8, + HTT_TAB = 9, // seems unused in almost all code HTT_LINKCOLOUR = 10, HTT_SOUND = 11, HTT_STRING = 12, @@ -49,8 +50,8 @@ namespace Text { }; struct LineLayout { - short unknown0; - short unknown1; + short leftBorder; + short rightBorder; short unknown2; }; @@ -75,7 +76,7 @@ namespace Text { int currentHelpSectionID; // 0x00000028 length: 4 int helpSectionHistoryStack[30]; // 0x0000002C length: 120 int counter; // 0x000000A4 length: 4 - undefined4 helpContentScrollOffsetY; // 0x000000A8 length: 4 + int helpContentScrollOffsetY; // 0x000000A8 length: 4 int topVisibleLineIndex; // 0x000000AC length: 4 undefined4 dialogX; // 0x000000B0 length: 4 undefined4 dialogY; // 0x000000B4 length: 4 @@ -89,7 +90,7 @@ namespace Text { undefined4 helpContentScrollY; // 0x000000D4 length: 4 int activeHelpHotspotIndex; // 0x000000D8 length: 4 undefined4 helpDialogSubMode; // 0x000000DC length: 4 - undefined4 useAlternateHelpTab; // 0x000000E0 length: 4 + BOOL useAlternateHelpTab; // 0x000000E0 length: 4 undefined4 isCustomTextMode; // 0x000000E4 length: 4 undefined4 useWideHelpLayout; // 0x000000E8 length: 4 undefined4 pendingTokenTypeToSkip; // 0x000000EC length: 4 diff --git a/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp b/src/OpenSHC/Text/TextEditorState/initializeAndLayoutHelpText.cpp index 44b86a79..99fef53e 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 00000000..837af17d --- /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; + } + } + } + +} +}