Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1390bbc
reimplement: SHC_3BB0A8C1_0x0045F130 100%
TheRedDaemon Sep 6, 2026
c9ba4de
reimplement: SHC_3BB0A8C1_0x0045D080 100%
TheRedDaemon Sep 6, 2026
f3593be
reimplement: SHC_3BB0A8C1_0x0045D0C0 100%
TheRedDaemon Sep 6, 2026
aed0b62
reimplement: SHC_3BB0A8C1_0x0045D140 100%
TheRedDaemon Sep 6, 2026
ee21369
reimplement: SHC_3BB0A8C1_0x0045D1A0 100%
TheRedDaemon Sep 6, 2026
93f4620
reimplement: SHC_3BB0A8C1_0x0045D200 100%
TheRedDaemon Sep 7, 2026
2082ac1
reimplement: SHC_3BB0A8C1_0x0045D370 100%
TheRedDaemon Sep 7, 2026
9fb6002
reimplement: SHC_3BB0A8C1_0x0045D3C0 100%
TheRedDaemon Sep 8, 2026
39376c9
reimplement: SHC_3BB0A8C1_0x0045D430 100%
TheRedDaemon Sep 8, 2026
07a1257
reimplement: SHC_3BB0A8C1_0x0045D690 100%
TheRedDaemon Sep 8, 2026
3e85a75
reimplement: SHC_3BB0A8C1_0x0045D6C0 100%
TheRedDaemon Sep 9, 2026
31b7b37
reimplement: SHC_3BB0A8C1_0x0045D200 update return type
TheRedDaemon Sep 9, 2026
0b45beb
reimplement: SHC_3BB0A8C1_0x0045D740 100%
TheRedDaemon Sep 9, 2026
c323912
reimplement: SHC_3BB0A8C1_0x0045D890 100%
TheRedDaemon Sep 9, 2026
fedc863
reimplement: SHC_3BB0A8C1_0x0045D8F0 100%
TheRedDaemon Sep 10, 2026
7c729b5
reimplement: SHC_3BB0A8C1_0x0045D950 100%
TheRedDaemon Sep 10, 2026
c678040
reimplement: SHC_3BB0A8C1_0x0045D990 100%
TheRedDaemon Sep 10, 2026
2522f42
reimplement: SHC_3BB0A8C1_0x0045D9E0 100%
TheRedDaemon Sep 10, 2026
425de6a
reimplement: SHC_3BB0A8C1_0x0045DA20 100%
TheRedDaemon Sep 10, 2026
eae57c3
reimplement: SHC_3BB0A8C1_0x0045DA40 100%
TheRedDaemon Sep 10, 2026
c0fead7
reimplement: SHC_3BB0A8C1_0x0045DA80 100%
TheRedDaemon Sep 11, 2026
4315629
reimplement: SHC_3BB0A8C1_0x0045DAE0 100%
TheRedDaemon Sep 11, 2026
831ed4b
reimplement: SHC_3BB0A8C1_0x0045DB40 100%
TheRedDaemon Sep 12, 2026
d64f00e
reimplement: SHC_3BB0A8C1_0x0045F080 and SHC_3BB0A8C1_0x0045F0D0 100%
TheRedDaemon Sep 12, 2026
52fa088
reimplement: SHC_3BB0A8C1_0x0045F240 100%
TheRedDaemon Sep 12, 2026
d78e1f5
reimplement: SHC_3BB0A8C1_0x0045F470 100%
TheRedDaemon Sep 12, 2026
7fac176
reimplement: SHC_3BB0A8C1_0x0045F580 100%
TheRedDaemon Sep 12, 2026
c438107
reimplement: SHC_3BB0A8C1_0x0045F5B0 99%
TheRedDaemon Sep 13, 2026
5a0346d
reimplement: SHC_3BB0A8C1_0x004614D0 100%
TheRedDaemon Sep 17, 2026
e3e3167
reimplement: SHC_3BB0A8C1_0x004613E0 100%
TheRedDaemon Sep 17, 2026
2f334d1
reimplement: SHC_3BB0A8C1_0x00461550 100%
TheRedDaemon Sep 17, 2026
f1b62c7
reimplement: SHC_3BB0A8C1_0x004619D0 100%
TheRedDaemon Sep 17, 2026
d474dae
reimplement: SHC_3BB0A8C1_0x00461A20 100%
TheRedDaemon Sep 17, 2026
2fb2060
reimplement: SHC_3BB0A8C1_0x00461B90 100%
TheRedDaemon Sep 17, 2026
7040855
reimplement: SHC_3BB0A8C1_0x00461CF0 100%
TheRedDaemon Sep 17, 2026
f31cff9
reimplement: SHC_3BB0A8C1_0x00461E50 100%
TheRedDaemon Sep 17, 2026
541382e
reimplement: SHC_3BB0A8C1_0x00461F90 100%
TheRedDaemon Sep 17, 2026
3a02655
reimplement: SHC_3BB0A8C1_0x004620F0 100%
TheRedDaemon Sep 17, 2026
06d02d0
reimplement: SHC_3BB0A8C1_0x00462150 100%
TheRedDaemon Sep 17, 2026
f5040f9
reimplement: SHC_3BB0A8C1_0x00462190 100%
TheRedDaemon Sep 17, 2026
886d4d6
reimplement: SHC_3BB0A8C1_0x0045FDC0 start clean up
TheRedDaemon Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions IMPLEMENTATION_CHEAT_SHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -196,6 +197,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.
Expand Down Expand Up @@ -262,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.

Expand Down
8 changes: 8 additions & 0 deletions src/OpenSHC/OS.func.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,13 @@ namespace OS_Func {
void(__cdecl*)(int _Code), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00583D55, &OpenSHC::OS::_exit)
_exit;

MACRO_FUNCTION_RESOLVER(int(__cdecl*)(FILE*, wchar_t const*, ...), REIMPLEMENTED_CRT,
Address::SHC_3BB0A8C1_0x005807A8, &OpenSHC::OS::_fwprintf)
_fwprintf;

MACRO_FUNCTION_RESOLVER(
long(__cdecl*)(wchar_t const*), REIMPLEMENTED_CRT, Address::SHC_3BB0A8C1_0x00580C0B, &OpenSHC::OS::__wtol)
__wtol;

} // namespace OS_Func
} // namespace OpenSHC
4 changes: 4 additions & 0 deletions src/OpenSHC/OS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,9 @@ namespace OS {

void __cdecl _exit(int _Code);

int _fwprintf(FILE* stream, wchar_t const* format, ...);

long __wtol(wchar_t const* str);

} // namespace OS
} // namespace OpenSHC
14 changes: 14 additions & 0 deletions src/OpenSHC/OS/OS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,19 @@ 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;
}

// STUB: STRONGHOLDCRUSADER 0x00580C0B
long __wtol(wchar_t const* str) { return _wtol(str); }

}
}
24 changes: 12 additions & 12 deletions src/OpenSHC/Text/TextEditorState.func.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ namespace Text {
findOrAddHelpSectionName;

MACRO_FUNCTION_RESOLVER(
uint (TextEditorState::*)(FILE*), false, Address::SHC_3BB0A8C1_0x0045D200, &TextEditorState::parseHLPPart)
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)
Expand Down Expand Up @@ -103,19 +103,19 @@ namespace Text {
&TextEditorState::saveHelpFileToResource)
saveHelpFileToResource;

MACRO_FUNCTION_RESOLVER(undefined4 (TextEditorState::*)(undefined4), false, Address::SHC_3BB0A8C1_0x0045F080,
&TextEditorState::getHelpTokenAdvanceLength)
getHelpTokenAdvanceLength;
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::insertHelpTextToken)
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)
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;

Expand Down Expand Up @@ -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;

Expand Down
Loading