From 2b9d5d50a343d5cd4a5afb4359d6a1e8ed34cf57 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:34 +0200 Subject: [PATCH 001/252] reimplement: SHC_3BB0A8C1_0x004F70D0 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/noop1.cpp | 16 ++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/noop1.cpp diff --git a/src/OpenSHC/Map/TileMapState/noop1.cpp b/src/OpenSHC/Map/TileMapState/noop1.cpp new file mode 100644 index 000000000..6e1eca8d6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/noop1.cpp @@ -0,0 +1,16 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F70D0 + void TileMapState::noop1(undefined4 param_1) { return; } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b80b8635f..4670da0ce 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38757,7 +38757,7 @@ SHC_3BB0A8C1_0x004F6FD0 | 0.0% | Pending SHC_3BB0A8C1_0x004F70B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F70D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F70D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F70E0 | 0.0% | Pending From 883bee35b6d154ec017675a221cc24347a3af180 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:35 +0200 Subject: [PATCH 002/252] reimplement: SHC_3BB0A8C1_0x004F70E0 100.00% Reimplemented --- .../Map/TileMapState/setMapRotation.cpp | 20 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setMapRotation.cpp diff --git a/src/OpenSHC/Map/TileMapState/setMapRotation.cpp b/src/OpenSHC/Map/TileMapState/setMapRotation.cpp new file mode 100644 index 000000000..c6e48ec9f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setMapRotation.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F70E0 + void TileMapState::setMapRotation(undefined4 newRotation) + { + this->DAT_FutureMapOrientation = newRotation; + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4670da0ce..35e8b860e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38759,7 +38759,7 @@ SHC_3BB0A8C1_0x004F70B0 | 0.0% | Pending SHC_3BB0A8C1_0x004F70D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F70E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F70E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F70F0 | 0.0% | Pending From 789fb233abdb8ef16d3468d3d590551ed0a251ea Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:35 +0200 Subject: [PATCH 003/252] reimplement: SHC_3BB0A8C1_0x004F70B0 100.00% Reimplemented --- .../Map/TileMapState/toggleFlatView.cpp | 23 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/toggleFlatView.cpp diff --git a/src/OpenSHC/Map/TileMapState/toggleFlatView.cpp b/src/OpenSHC/Map/TileMapState/toggleFlatView.cpp new file mode 100644 index 000000000..64545d3f6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/toggleFlatView.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F70B0 + void TileMapState::toggleFlatView(int param_1) + { + if (param_1 != this->flatViewToggleValue1) { + this->flatViewToggleValue1 = param_1; + this->flatViewToggleValue2 = param_1; + } + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 35e8b860e..d00be7c2b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38755,7 +38755,7 @@ SHC_3BB0A8C1_0x004F6F90 | 0.0% | Pending SHC_3BB0A8C1_0x004F6FD0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F70B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F70B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F70D0 | 100.0% | Reimplemented From c82f7833ab55bde66e0fb9dc2fdc340195784455 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:35 +0200 Subject: [PATCH 004/252] reimplement: SHC_3BB0A8C1_0x00401060 100.00% Reimplemented --- ...sEntityDamageToBuildingCollateralThunk.cpp | 23 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateralThunk.cpp diff --git a/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateralThunk.cpp b/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateralThunk.cpp new file mode 100644 index 000000000..e8d1816ec --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateralThunk.cpp @@ -0,0 +1,23 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:56:35.138000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00401060 + void TileMapState::processEntityDamageToBuildingCollateralThunk( + int tile, uint x_2, uint y_2, int damage, int playerID, undefined4 unused) + { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::processEntityDamageToBuildingCollateral, this)( + tile, x_2, y_2, damage, playerID, (undefined4)((int)(unused)), 0); + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d00be7c2b..37b3b619a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -385,7 +385,7 @@ SHC_3BB0A8C1_0x00401000 | 0.0% | Pending SHC_3BB0A8C1_0x00401040 | 0.0% | Pending -SHC_3BB0A8C1_0x00401060 | 0.0% | Pending +SHC_3BB0A8C1_0x00401060 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00401090 | 0.0% | Pending From d259c64d8ea2ae4548a53102eecb8ec5efaaf228 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:36 +0200 Subject: [PATCH 005/252] reimplement: SHC_3BB0A8C1_0x005017A0 100.00% Reimplemented --- .../TileMapState/forceFullTileMapRedraw.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/forceFullTileMapRedraw.cpp diff --git a/src/OpenSHC/Map/TileMapState/forceFullTileMapRedraw.cpp b/src/OpenSHC/Map/TileMapState/forceFullTileMapRedraw.cpp new file mode 100644 index 000000000..f70f85ee4 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/forceFullTileMapRedraw.cpp @@ -0,0 +1,24 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005017A0 + void TileMapState::forceFullTileMapRedraw() + { + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + this->forceUpdateTextureTilemap = 1; + this->forceUpdateGFXLayers = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setChangedLayerToThreeAndMapping0x40x40, this)(); + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 37b3b619a..ca98a101d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41539,7 +41539,7 @@ SHC_3BB0A8C1_0x00501730 | 0.0% | Pending SHC_3BB0A8C1_0x00501760 | 0.0% | Pending -SHC_3BB0A8C1_0x005017A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005017A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005017C0 | 0.0% | Pending From 34f4ecafb3030b69c7b64baf767cd26986dded0b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:36 +0200 Subject: [PATCH 006/252] reimplement: SHC_3BB0A8C1_0x004FC7C0 78.95% setg vs sbb/neg --- .../TileMapState/isCliffDropInDirection.cpp | 21 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isCliffDropInDirection.cpp diff --git a/src/OpenSHC/Map/TileMapState/isCliffDropInDirection.cpp b/src/OpenSHC/Map/TileMapState/isCliffDropInDirection.cpp new file mode 100644 index 000000000..818805103 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isCliffDropInDirection.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC7C0 + BOOLEnum TileMapState::isCliffDropInDirection(int tile, undefined4 param_2, int y) + { + int direction = (this->field84_0x5548a4 + 4) % 8; + return (uint)this->HeightLayer[tile] + > (uint)(this->HeightLayer[this->directionTranslationMatrix[y][direction] + tile] + 0x14); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ca98a101d..c284561fc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41091,7 +41091,7 @@ SHC_3BB0A8C1_0x004FC490 | 0.0% | Pending SHC_3BB0A8C1_0x004FC650 | 0.0% | Pending -SHC_3BB0A8C1_0x004FC7C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC7C0 | 79.0% | setg vs sbb/neg SHC_3BB0A8C1_0x004FC810 | 0.0% | Pending From 9e435330afc94eaf34d636a440ca4872f11a08af Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:36 +0200 Subject: [PATCH 007/252] reimplement: SHC_3BB0A8C1_0x00409300 100.00% Reimplemented --- .../processDamageToBuildingThunk.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/processDamageToBuildingThunk.cpp diff --git a/src/OpenSHC/Map/TileMapState/processDamageToBuildingThunk.cpp b/src/OpenSHC/Map/TileMapState/processDamageToBuildingThunk.cpp new file mode 100644 index 000000000..22790ea80 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/processDamageToBuildingThunk.cpp @@ -0,0 +1,24 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00409300 + BOOLEnum TileMapState::processDamageToBuildingThunk(int targetedTile, uint targetedTileX, uint targetedTileY, + int damage, int param_5, int playerID, BOOLEnum aiBuildDelayRelated) + { + BOOLEnum BVar1; + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::processDamageToBuilding, this)( + targetedTile, targetedTileX, targetedTileY, damage, param_5, playerID, aiBuildDelayRelated, 0); + return BVar1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c284561fc..66eba9716 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -2601,7 +2601,7 @@ SHC_3BB0A8C1_0x004092C0 | 0.0% | Pending SHC_3BB0A8C1_0x004092E0 | 0.0% | Pending -SHC_3BB0A8C1_0x00409300 | 0.0% | Pending +SHC_3BB0A8C1_0x00409300 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00409330 | 0.0% | Pending From f3f6230d155f006431d57458f4633f35fa24e04d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:37 +0200 Subject: [PATCH 008/252] reimplement: SHC_3BB0A8C1_0x005011A0 100.00% Reimplemented --- .../spreadBrazierPlacementAlgorithm.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/spreadBrazierPlacementAlgorithm.cpp diff --git a/src/OpenSHC/Map/TileMapState/spreadBrazierPlacementAlgorithm.cpp b/src/OpenSHC/Map/TileMapState/spreadBrazierPlacementAlgorithm.cpp new file mode 100644 index 000000000..0d75c3e2a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/spreadBrazierPlacementAlgorithm.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005011A0 + void TileMapState::spreadBrazierPlacementAlgorithm(int playerID, uint x, uint y) + { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::spreadAlgorithmForFlagsAndBraziersUnk, + DAT_PathFindingState::ptr)(playerID, x, y, 4, 1); + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 66eba9716..5a3e271cf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41513,7 +41513,7 @@ SHC_3BB0A8C1_0x00501110 | 0.0% | Pending SHC_3BB0A8C1_0x00501180 | 0.0% | Pending -SHC_3BB0A8C1_0x005011A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005011A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005011C0 | 0.0% | Pending From 6656ef7a80d13e553ac460d0805f946e25bd010e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:37 +0200 Subject: [PATCH 009/252] reimplement: SHC_3BB0A8C1_0x00512920 100.00% Reimplemented --- .../processMapOrientationChange.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/processMapOrientationChange.cpp diff --git a/src/OpenSHC/Map/TileMapState/processMapOrientationChange.cpp b/src/OpenSHC/Map/TileMapState/processMapOrientationChange.cpp new file mode 100644 index 000000000..a0e54f346 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/processMapOrientationChange.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00512920 + void TileMapState::processMapOrientationChange() + { + if ((int)this->DAT_FutureMapOrientation >= 8) { + return; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::changeMapOrientation, this)(this->DAT_FutureMapOrientation); + this->DAT_FutureMapOrientation = 8; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5a3e271cf..b04c52a1d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44739,7 +44739,7 @@ SHC_3BB0A8C1_0x005127B0 | 0.0% | Pending SHC_3BB0A8C1_0x005127D0 | 0.0% | Pending -SHC_3BB0A8C1_0x00512920 | 0.0% | Pending +SHC_3BB0A8C1_0x00512920 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00512940 | 0.0% | Pending From 2300d92e54f1a19280b790d7b3c517ef44f45504 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:37 +0200 Subject: [PATCH 010/252] reimplement: SHC_3BB0A8C1_0x00500720 100.00% Reimplemented --- .../TileMapState/setMoatVisualStateAtTile.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setMoatVisualStateAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/setMoatVisualStateAtTile.cpp b/src/OpenSHC/Map/TileMapState/setMoatVisualStateAtTile.cpp new file mode 100644 index 000000000..8786e5c85 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setMoatVisualStateAtTile.cpp @@ -0,0 +1,25 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500720 + void TileMapState::setMoatVisualStateAtTile(int tile, undefined4 zeroOrTwo) + { + int iVar1; + iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(tile); + if (iVar1 != 0) { + this->moats[iVar1].zeroOrTwo = (short)zeroOrTwo; + } + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b04c52a1d..c5fb95bfb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41449,7 +41449,7 @@ SHC_3BB0A8C1_0x00500680 | 0.0% | Pending SHC_3BB0A8C1_0x005006C0 | 0.0% | Pending -SHC_3BB0A8C1_0x00500720 | 0.0% | Pending +SHC_3BB0A8C1_0x00500720 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500750 | 0.0% | Pending From 744e6ba303ea3ed966f67d58c87f3bd42fd57e4a Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:38 +0200 Subject: [PATCH 011/252] reimplement: SHC_3BB0A8C1_0x00501180 100.00% Reimplemented --- .../spreadFlagPlacementAlgorithm.cpp | 27 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/spreadFlagPlacementAlgorithm.cpp diff --git a/src/OpenSHC/Map/TileMapState/spreadFlagPlacementAlgorithm.cpp b/src/OpenSHC/Map/TileMapState/spreadFlagPlacementAlgorithm.cpp new file mode 100644 index 000000000..ca401342c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/spreadFlagPlacementAlgorithm.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501180 + int TileMapState::spreadFlagPlacementAlgorithm(int param_1, uint param_2, uint param_3) + { + int iVar1; + iVar1 + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::spreadAlgorithmForFlagsAndBraziersUnk, + DAT_PathFindingState::ptr)(param_1, param_2, param_3, 4, 0); + return iVar1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c5fb95bfb..0a93e202e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41511,7 +41511,7 @@ SHC_3BB0A8C1_0x005010E0 | 0.0% | Pending SHC_3BB0A8C1_0x00501110 | 0.0% | Pending -SHC_3BB0A8C1_0x00501180 | 0.0% | Pending +SHC_3BB0A8C1_0x00501180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005011A0 | 100.0% | Reimplemented From af088b93cc3d558bb4c69fac43d367d6342bd53f Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:11:38 +0200 Subject: [PATCH 012/252] reimplement: SHC_3BB0A8C1_0x005002D0 100.00% Reimplemented --- .../Map/TileMapState/clearMoatData.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearMoatData.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearMoatData.cpp b/src/OpenSHC/Map/TileMapState/clearMoatData.cpp new file mode 100644 index 000000000..13d0818ec --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearMoatData.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005002D0 + void TileMapState::clearMoatData(uint moatID) + { + if (moatID > 15999) { + return; + } + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(Moat), 0, &this->moats[moatID]); + this->moatTileCount = this->moatTileCount - 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0a93e202e..3bdce55d1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41431,7 +41431,7 @@ SHC_3BB0A8C1_0x00500250 | 0.0% | Pending SHC_3BB0A8C1_0x00500290 | 0.0% | Pending -SHC_3BB0A8C1_0x005002D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005002D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500310 | 0.0% | Pending From 131649434d9c8c11e4565e6fda8a19ab784ddd90 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:03 +0200 Subject: [PATCH 013/252] reimplement: SHC_3BB0A8C1_0x004FBC30 100.00% Reimplemented --- .../getCastleBuildRangeForMapSize.cpp | 29 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getCastleBuildRangeForMapSize.cpp diff --git a/src/OpenSHC/Map/TileMapState/getCastleBuildRangeForMapSize.cpp b/src/OpenSHC/Map/TileMapState/getCastleBuildRangeForMapSize.cpp new file mode 100644 index 000000000..467ff840d --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getCastleBuildRangeForMapSize.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FBC30 + undefined4 TileMapState::getCastleBuildRangeForMapSize() + { + switch (this->mapSize) { + case 160: + return 45; + case 200: + return 50; + case 300: + return 60; + case 400: + return 70; + } + return 70; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3bdce55d1..499b0887d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40583,7 +40583,7 @@ SHC_3BB0A8C1_0x004FB990 | 0.0% | Pending SHC_3BB0A8C1_0x004FB9E0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FBC30 | 0.0% | Pending +SHC_3BB0A8C1_0x004FBC30 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004FBC6C | 0.0% | Pending From 3afc34a3686c2cdeb51ab3ab46db057dd8ff7062 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:03 +0200 Subject: [PATCH 014/252] reimplement: SHC_3BB0A8C1_0x00504EE0 38.46% needs callee LTCG (ecx reuse) --- ...updateBuildingPlacementRotationPreview.cpp | 26 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateBuildingPlacementRotationPreview.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateBuildingPlacementRotationPreview.cpp b/src/OpenSHC/Map/TileMapState/updateBuildingPlacementRotationPreview.cpp new file mode 100644 index 000000000..d56cfad16 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateBuildingPlacementRotationPreview.cpp @@ -0,0 +1,26 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00504EE0 + void TileMapState::updateBuildingPlacementRotationPreview(int param_1, int param_2) + { + BOOLEnum previousPlacementFail = this->buildingPlacementFail; + this->buildingPlacementFail = FALSE; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::determineBuildingPlacementRotation, this)(param_1, param_2); + this->buildingPlacementFail = previousPlacementFail; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 499b0887d..c939bfbbf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42067,7 +42067,7 @@ SHC_3BB0A8C1_0x00504ED0 | 0.0% | Pending SHC_3BB0A8C1_0x00504ED1 | 0.0% | Pending -SHC_3BB0A8C1_0x00504EE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00504EE0 | 38.5% | needs callee LTCG (ecx reuse) SHC_3BB0A8C1_0x00504F10 | 0.0% | Pending From 342409c043a18e0d0aecef1dca1d93106c683594 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:04 +0200 Subject: [PATCH 015/252] reimplement: SHC_3BB0A8C1_0x004F9930 100.00% Reimplemented --- .../TileMapState/isFootprintIndexOnEdge.cpp | 34 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isFootprintIndexOnEdge.cpp diff --git a/src/OpenSHC/Map/TileMapState/isFootprintIndexOnEdge.cpp b/src/OpenSHC/Map/TileMapState/isFootprintIndexOnEdge.cpp new file mode 100644 index 000000000..2c0cff146 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isFootprintIndexOnEdge.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9930 + BOOLEnum TileMapState::isFootprintIndexOnEdge(int counter, int size) + { + if (size < 3) { + return TRUE; + } + if (counter < size) { + return TRUE; + } + if (counter >= (size - 1) * size) { + return TRUE; + } + if (counter % size == 0) { + return TRUE; + } + return counter % size == size - 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c939bfbbf..c0618985b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39407,7 +39407,7 @@ SHC_3BB0A8C1_0x004F9920 | 0.0% | Pending SHC_3BB0A8C1_0x004F9924 | 0.0% | Pending -SHC_3BB0A8C1_0x004F9930 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9930 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F9980 | 0.0% | Pending From 9ca15c14c74d40cbffd0e5438ce3f53d9c4412a2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:04 +0200 Subject: [PATCH 016/252] reimplement: SHC_3BB0A8C1_0x005005F0 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/clearMoat.cpp | 33 ++++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearMoat.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearMoat.cpp b/src/OpenSHC/Map/TileMapState/clearMoat.cpp new file mode 100644 index 000000000..3e42a0053 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearMoat.cpp @@ -0,0 +1,33 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005005F0 + void TileMapState::clearMoat(int tile) + { + if ((this->LogicLayer[tile] & L_MOAT_DUG_OR_PLANNED) == 0) { + return; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT_DUG_OR_PLANNED; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c0618985b..214493bcf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41441,7 +41441,7 @@ SHC_3BB0A8C1_0x005003D0 | 0.0% | Pending SHC_3BB0A8C1_0x00500500 | 0.0% | Pending -SHC_3BB0A8C1_0x005005F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005005F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500640 | 0.0% | Pending From b22b38cf0cc81963ca8201e165b9eb0486b162ff Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:04 +0200 Subject: [PATCH 017/252] reimplement: SHC_3BB0A8C1_0x004F8530 100.00% Reimplemented --- .../countLogicPropertyInSurroundingTiles.cpp | 31 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/countLogicPropertyInSurroundingTiles.cpp diff --git a/src/OpenSHC/Map/TileMapState/countLogicPropertyInSurroundingTiles.cpp b/src/OpenSHC/Map/TileMapState/countLogicPropertyInSurroundingTiles.cpp new file mode 100644 index 000000000..59f262ebd --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/countLogicPropertyInSurroundingTiles.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8530 + void TileMapState::countLogicPropertyInSurroundingTiles(int tile, int y, uint logic1) + { + this->DAT_CardinalTilesAroundTile = 0; + if ((this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & logic1) != 0) { + this->DAT_CardinalTilesAroundTile++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & logic1) != 0) { + this->DAT_CardinalTilesAroundTile++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & logic1) != 0) { + this->DAT_CardinalTilesAroundTile++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & logic1) != 0) { + this->DAT_CardinalTilesAroundTile++; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 214493bcf..3da236266 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39355,7 +39355,7 @@ SHC_3BB0A8C1_0x004F8523 | 0.0% | Pending SHC_3BB0A8C1_0x004F8524 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8530 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8530 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F85B0 | 0.0% | Pending From 5f592fdb6f7f0a84bd813d977d9f5be610ea6ee0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:05 +0200 Subject: [PATCH 018/252] reimplement: SHC_3BB0A8C1_0x00500750 100.00% Reimplemented --- .../setMoatOwnerForAllMatching.cpp | 23 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setMoatOwnerForAllMatching.cpp diff --git a/src/OpenSHC/Map/TileMapState/setMoatOwnerForAllMatching.cpp b/src/OpenSHC/Map/TileMapState/setMoatOwnerForAllMatching.cpp new file mode 100644 index 000000000..d68ba14a4 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setMoatOwnerForAllMatching.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500750 + void TileMapState::setMoatOwnerForAllMatching(int param_1, undefined4 param_2) + { + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner != '\0' && this->moats[moatID].owner == param_1) { + this->moats[moatID].owner = (char)param_2; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3da236266..25b399fd1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41451,7 +41451,7 @@ SHC_3BB0A8C1_0x005006C0 | 0.0% | Pending SHC_3BB0A8C1_0x00500720 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500750 | 0.0% | Pending +SHC_3BB0A8C1_0x00500750 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500790 | 0.0% | Pending From 0eb7c04cd4b646d5e3ef0ffa727a6c8601c5f7ab Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:05 +0200 Subject: [PATCH 019/252] reimplement: SHC_3BB0A8C1_0x005000A0 100.00% Reimplemented --- .../TileMapState/recountTotalOwnedMoats.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/recountTotalOwnedMoats.cpp diff --git a/src/OpenSHC/Map/TileMapState/recountTotalOwnedMoats.cpp b/src/OpenSHC/Map/TileMapState/recountTotalOwnedMoats.cpp new file mode 100644 index 000000000..674e823f7 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/recountTotalOwnedMoats.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005000A0 + void TileMapState::recountTotalOwnedMoats() + { + this->currentMoatCount = 0; + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner != '\0') { + this->currentMoatCount = moatID + 1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 25b399fd1..8772131e6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41419,7 +41419,7 @@ SHC_3BB0A8C1_0x00500090 | 0.0% | Pending SHC_3BB0A8C1_0x00500091 | 0.0% | Pending -SHC_3BB0A8C1_0x005000A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005000A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005000E0 | 0.0% | Pending From f71bb29c6841ca7061f98a568919dd772a08d379 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:05 +0200 Subject: [PATCH 020/252] reimplement: SHC_3BB0A8C1_0x004F81D0 100.00% Reimplemented --- .../TileMapState/resetTileToDefaultState.cpp | 36 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetTileToDefaultState.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetTileToDefaultState.cpp b/src/OpenSHC/Map/TileMapState/resetTileToDefaultState.cpp new file mode 100644 index 000000000..60e41b77a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetTileToDefaultState.cpp @@ -0,0 +1,36 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F81D0 + void TileMapState::resetTileToDefaultState(int param_1, uint param_2, uint param_3) + { + this->LogicLayer[param_1] = this->LogicLayer[param_1] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_STAIRS | L_UNKNOWN_WALL_RELATED | L_CRENEL_VARIATIONUnk); + this->HeightLayer[param_1] = this->DefaultHeightLayer[param_1]; + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, DAT_EntityState::ptr)( + param_1); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(5, param_2, param_3); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8772131e6..c6e6c38cf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38791,7 +38791,7 @@ SHC_3BB0A8C1_0x004F80E0 | 0.0% | Pending SHC_3BB0A8C1_0x004F8160 | 0.0% | Pending -SHC_3BB0A8C1_0x004F81D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F81D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F8210 | 0.0% | Pending From 8b5105f9071c1b77b61138dbf34baaa3110507b0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:06 +0200 Subject: [PATCH 021/252] reimplement: SHC_3BB0A8C1_0x004F6AE0 100.00% Reimplemented --- ...etChangedLayerToThreeAndMapping0x40x40.cpp | 29 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setChangedLayerToThreeAndMapping0x40x40.cpp diff --git a/src/OpenSHC/Map/TileMapState/setChangedLayerToThreeAndMapping0x40x40.cpp b/src/OpenSHC/Map/TileMapState/setChangedLayerToThreeAndMapping0x40x40.cpp new file mode 100644 index 000000000..69d856d91 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setChangedLayerToThreeAndMapping0x40x40.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6AE0 + void TileMapState::setChangedLayerToThreeAndMapping0x40x40() + { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(this->ChangedLayer), 3, this->ChangedLayer); + MACRO_CALL(OpenSHC::OS_Func::_memset)(this->mapping40x40, 3, sizeof(this->mapping40x40)); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setChangedLayerZeroBasedOn40x40Layer, + DAT_PathFindingState::ptr)(1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c6e6c38cf..06a5800fc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38739,7 +38739,7 @@ SHC_3BB0A8C1_0x004F6A70 | 0.0% | Pending SHC_3BB0A8C1_0x004F6A80 | 0.0% | Pending -SHC_3BB0A8C1_0x004F6AE0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6AE0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F6B20 | 0.0% | Pending From 9389e9827d30462fb2c9641974238c717d3cbbd9 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:06 +0200 Subject: [PATCH 022/252] reimplement: SHC_3BB0A8C1_0x00500850 100.00% Reimplemented --- .../TileMapState/getPitchDitchIDForTile.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp b/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp new file mode 100644 index 000000000..efa5983db --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500850 + int TileMapState::getPitchDitchIDForTile(int tile) + { + for (int pitchDitchID = 1; pitchDitchID < (int)this->maxPitchDitchCount; pitchDitchID++) { + if (this->pitchDitches[pitchDitchID].owner != 0 && tile == this->pitchDitches[pitchDitchID].tile) { + return pitchDitchID; + } + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 06a5800fc..43dacd878 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41459,7 +41459,7 @@ SHC_3BB0A8C1_0x005007D0 | 0.0% | Pending SHC_3BB0A8C1_0x00500800 | 0.0% | Pending -SHC_3BB0A8C1_0x00500850 | 0.0% | Pending +SHC_3BB0A8C1_0x00500850 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500890 | 0.0% | Pending From 9e78661390d359fd889000e3e123bf0f958f05a7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:07 +0200 Subject: [PATCH 023/252] reimplement: SHC_3BB0A8C1_0x00500290 100.00% Reimplemented --- .../TileMapState/returnMoatIDForPlayerIDs.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp diff --git a/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp b/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp new file mode 100644 index 000000000..be9576c69 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500290 + int TileMapState::returnMoatIDForPlayerIDs(int playerID, int playerID2) + { + for (int moatID = 1; moatID < this->currentMoatCount; moatID++) { + if (*(int*)&this->moats[moatID].tile == playerID && this->moats[moatID].owner == playerID2) { + return moatID; + } + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 43dacd878..9032d1ed3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41429,7 +41429,7 @@ SHC_3BB0A8C1_0x00500210 | 0.0% | Pending SHC_3BB0A8C1_0x00500250 | 0.0% | Pending -SHC_3BB0A8C1_0x00500290 | 0.0% | Pending +SHC_3BB0A8C1_0x00500290 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005002D0 | 100.0% | Reimplemented From f08b879ec23099b81bb251d885411624a906672c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:07 +0200 Subject: [PATCH 024/252] reimplement: SHC_3BB0A8C1_0x00500250 100.00% Reimplemented --- .../TileMapState/returnOwnedMoatAtTile.cpp | 24 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp b/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp new file mode 100644 index 000000000..e66161e43 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500250 + int TileMapState::returnOwnedMoatAtTile(int targetedTile) + { + for (int moatID = 1; moatID < this->currentMoatCount; moatID++) { + if (this->moats[moatID].owner != 0 && *(int*)&this->moats[moatID].tile == targetedTile) { + return moatID; + } + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9032d1ed3..b45f0ac9f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41427,7 +41427,7 @@ SHC_3BB0A8C1_0x00500180 | 0.0% | Pending SHC_3BB0A8C1_0x00500210 | 0.0% | Pending -SHC_3BB0A8C1_0x00500250 | 0.0% | Pending +SHC_3BB0A8C1_0x00500250 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500290 | 100.0% | Reimplemented From 98973a6cd3ef93caa64574996953ee8a85b03fc5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:07 +0200 Subject: [PATCH 025/252] reimplement: SHC_3BB0A8C1_0x00511020 100.00% Reimplemented --- .../Map/TileMapState/updateMacroLayer.cpp | 45 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp b/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp new file mode 100644 index 000000000..04276859e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp @@ -0,0 +1,45 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_BEACH; + using OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_MEDIUM; + using OpenSHC::Map::LogicHelpers::L2_SCRUB; + using OpenSHC::Map::LogicHelpers::L_DEFAULT_EARTH_OR_TEXTURE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_NONE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00511020 + void TileMapState::updateMacroLayer() + { + if ((int)this->forceUpdateMacroLayerFlag <= 0) { + return; + } + + this->forceUpdateMacroLayerFlag = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)( + L_DEFAULT_EARTH_OR_TEXTURE, L2_SCRUB, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)(L_MARSH, L_NONE, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)( + L_NONE, L2_EARTH_AND_STONES, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)(L_NONE, L2_OASIS_GRASS, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)(L_NONE, L2_BEACH, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)(L_NONE, L2_PLATEAU_MEDIUM, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated, this)(L_NONE, L2_PLATEAU_HIGH, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateMacroLayerRelated2, this)(); + this->forceUpdateTextureTilemap = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b45f0ac9f..674e67cd7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44173,7 +44173,7 @@ SHC_3BB0A8C1_0x00511018 | 0.0% | Pending SHC_3BB0A8C1_0x0051101C | 0.0% | Pending -SHC_3BB0A8C1_0x00511020 | 0.0% | Pending +SHC_3BB0A8C1_0x00511020 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005110B0 | 0.0% | Pending From bbe1fc1f35225ecf2c360c219db414028672ede3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:36:08 +0200 Subject: [PATCH 026/252] reimplement: SHC_3BB0A8C1_0x004F8640 40.00% regalloc: extra edi --- .../TileMapState/isTileEnclosedByWalls.cpp | 38 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isTileEnclosedByWalls.cpp diff --git a/src/OpenSHC/Map/TileMapState/isTileEnclosedByWalls.cpp b/src/OpenSHC/Map/TileMapState/isTileEnclosedByWalls.cpp new file mode 100644 index 000000000..e649218d0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isTileEnclosedByWalls.cpp @@ -0,0 +1,38 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8640 + undefined4 TileMapState::isTileEnclosedByWalls(int tile, int y) + { + if ((this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & L_STOCKPILEUnk) == 0) { + return 1; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & L_STOCKPILEUnk) == 0) { + return 1; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & L_STOCKPILEUnk) == 0) { + return 1; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & L_STOCKPILEUnk) == 0) { + return 1; + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 674e67cd7..8e28e8715 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39359,7 +39359,7 @@ SHC_3BB0A8C1_0x004F8530 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F85B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8640 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8640 | 40.0% | regalloc: extra edi SHC_3BB0A8C1_0x004F86D0 | 0.0% | Pending From 45c882ea4e9fedcd74aa5292feda3dc93f5cc777 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:51 +0200 Subject: [PATCH 027/252] reimplement: SHC_3BB0A8C1_0x004FA9D0 43.64% ecx not kept across callee --- .../markBuildingFootprintFlag.cpp | 33 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/markBuildingFootprintFlag.cpp diff --git a/src/OpenSHC/Map/TileMapState/markBuildingFootprintFlag.cpp b/src/OpenSHC/Map/TileMapState/markBuildingFootprintFlag.cpp new file mode 100644 index 000000000..11a026e86 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/markBuildingFootprintFlag.cpp @@ -0,0 +1,33 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA9D0 + void TileMapState::markBuildingFootprintFlag(int param_1, int param_2, int param_3) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_3); + buildingSizeTileIndex++; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_2].addXgetTile + + this->buildingX + param_1; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_PLAIN1_AND_FARM; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfff3; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8e28e8715..4c743dac8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40347,7 +40347,7 @@ SHC_3BB0A8C1_0x004FA760 | 0.0% | Pending SHC_3BB0A8C1_0x004FA8D0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FA9D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA9D0 | 43.6% | ecx not kept across callee SHC_3BB0A8C1_0x004FAA30 | 0.0% | Pending From 57eb676b3597314f9b86cb20d851ff27e1107ba4 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:51 +0200 Subject: [PATCH 028/252] reimplement: SHC_3BB0A8C1_0x00500680 100.00% Reimplemented --- .../Map/TileMapState/resetMoatArray.cpp | 26 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetMoatArray.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetMoatArray.cpp b/src/OpenSHC/Map/TileMapState/resetMoatArray.cpp new file mode 100644 index 000000000..6777783f0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetMoatArray.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500680 + void TileMapState::resetMoatArray() + { + for (int moatID = 0; moatID < 16000; moatID++) { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(Moat), 0, &this->moats[moatID]); + } + this->moatTileCount = 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4c743dac8..7bf861ab3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41445,7 +41445,7 @@ SHC_3BB0A8C1_0x005005F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500640 | 0.0% | Pending -SHC_3BB0A8C1_0x00500680 | 0.0% | Pending +SHC_3BB0A8C1_0x00500680 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005006C0 | 0.0% | Pending From cab3d797a05a295674e12221a9665396ea047951 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:52 +0200 Subject: [PATCH 029/252] reimplement: SHC_3BB0A8C1_0x005007D0 100.00% Reimplemented --- .../Map/TileMapState/resetPitchDitchArray.cpp | 26 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetPitchDitchArray.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetPitchDitchArray.cpp b/src/OpenSHC/Map/TileMapState/resetPitchDitchArray.cpp new file mode 100644 index 000000000..4baf6e027 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetPitchDitchArray.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005007D0 + void TileMapState::resetPitchDitchArray() + { + this->maxPitchDitchCount = 4000; + for (int pitchDitchID = 0; pitchDitchID < 4000; pitchDitchID++) { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(PitchDitch), 0, &this->pitchDitches[pitchDitchID]); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7bf861ab3..a15d184a8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41455,7 +41455,7 @@ SHC_3BB0A8C1_0x00500750 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500790 | 0.0% | Pending -SHC_3BB0A8C1_0x005007D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005007D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500800 | 0.0% | Pending From 6f07c4c74371f1a624b2e9bafbd4ce9d2219c332 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:52 +0200 Subject: [PATCH 030/252] reimplement: SHC_3BB0A8C1_0x004F6F90 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/setMapSize.cpp | 30 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setMapSize.cpp diff --git a/src/OpenSHC/Map/TileMapState/setMapSize.cpp b/src/OpenSHC/Map/TileMapState/setMapSize.cpp new file mode 100644 index 000000000..9e6b379e6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setMapSize.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6F90 + void TileMapState::setMapSize(int size) + { + int index = 0; + while (size <= DAT_TerrainDefinedData::instance.MapSizes[index]) { + index++; + } + + if (DAT_TerrainDefinedData::instance.MapSizes[index] == -1) { + this->mapSize = DAT_TerrainDefinedData::instance.MapSizes[0]; + return; + } + this->mapSize = DAT_TerrainDefinedData::instance.MapSizes[index]; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a15d184a8..b7c559609 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38751,7 +38751,7 @@ SHC_3BB0A8C1_0x004F6CF0 | 0.0% | Pending SHC_3BB0A8C1_0x004F6DC0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F6F90 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6F90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F6FD0 | 0.0% | Pending From 208ac6c7f78976bf5d436502fdb8ef656027501d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:53 +0200 Subject: [PATCH 031/252] reimplement: SHC_3BB0A8C1_0x00503720 100.00% Reimplemented --- .../setupBuildingSizeIndexMapping.cpp | 33 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMapping.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMapping.cpp b/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMapping.cpp new file mode 100644 index 000000000..136526442 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMapping.cpp @@ -0,0 +1,33 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00503720 + void TileMapState::setupBuildingSizeIndexMapping() + { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(1); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(2); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(3); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(4); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(5); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(6); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(7); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(8); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(9); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(10); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(11); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(12); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMappingForBuildingWithSize, this)(13); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b7c559609..2fafabf49 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41653,7 +41653,7 @@ SHC_3BB0A8C1_0x00503492 | 0.0% | Pending SHC_3BB0A8C1_0x005034A0 | 0.0% | Pending -SHC_3BB0A8C1_0x00503720 | 0.0% | Pending +SHC_3BB0A8C1_0x00503720 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005037B0 | 0.0% | Pending From 1eb22057d60fa982f171141b4bb1952970d7a843 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:53 +0200 Subject: [PATCH 032/252] reimplement: SHC_3BB0A8C1_0x004FAD20 45.28% ecx not kept across callee --- .../unmarkBuildingFootprintFlag.cpp | 32 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/unmarkBuildingFootprintFlag.cpp diff --git a/src/OpenSHC/Map/TileMapState/unmarkBuildingFootprintFlag.cpp b/src/OpenSHC/Map/TileMapState/unmarkBuildingFootprintFlag.cpp new file mode 100644 index 000000000..4d7b79030 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/unmarkBuildingFootprintFlag.cpp @@ -0,0 +1,32 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAD20 + void TileMapState::unmarkBuildingFootprintFlag(int param_1, int param_2, int param_3) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_3); + buildingSizeTileIndex++; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_2].addXgetTile + + this->buildingX + param_1; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN1_AND_FARM; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2fafabf49..8baa75cd0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40359,7 +40359,7 @@ SHC_3BB0A8C1_0x004FAB70 | 0.0% | Pending SHC_3BB0A8C1_0x004FAC70 | 0.0% | Pending -SHC_3BB0A8C1_0x004FAD20 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAD20 | 45.3% | ecx not kept across callee SHC_3BB0A8C1_0x004FAD70 | 0.0% | Pending From fd27b50f29bd9b5af3271af85baf6bc48a550996 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:54 +0200 Subject: [PATCH 033/252] reimplement: SHC_3BB0A8C1_0x00500790 100.00% Reimplemented --- .../Map/TileMapState/swapMoatOwnership.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/swapMoatOwnership.cpp diff --git a/src/OpenSHC/Map/TileMapState/swapMoatOwnership.cpp b/src/OpenSHC/Map/TileMapState/swapMoatOwnership.cpp new file mode 100644 index 000000000..6235ce62f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/swapMoatOwnership.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500790 + void TileMapState::swapMoatOwnership(int param_1, int param_2) + { + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner == 0) { + continue; + } + if (this->moats[moatID].owner == param_1) { + this->moats[moatID].owner = (char)param_2; + } else if (this->moats[moatID].owner == param_2) { + this->moats[moatID].owner = (char)param_1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8baa75cd0..57a5f44ec 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41453,7 +41453,7 @@ SHC_3BB0A8C1_0x00500720 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500750 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500790 | 0.0% | Pending +SHC_3BB0A8C1_0x00500790 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005007D0 | 100.0% | Reimplemented From c0bfe4d883e4417ed4c0fc0c21579b3b1691f0e8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:54 +0200 Subject: [PATCH 034/252] reimplement: SHC_3BB0A8C1_0x00500940 100.00% Reimplemented --- .../Map/TileMapState/swapPitchOwnership.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/swapPitchOwnership.cpp diff --git a/src/OpenSHC/Map/TileMapState/swapPitchOwnership.cpp b/src/OpenSHC/Map/TileMapState/swapPitchOwnership.cpp new file mode 100644 index 000000000..76073ddfc --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/swapPitchOwnership.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500940 + void TileMapState::swapPitchOwnership(int param_1, int param_2) + { + for (int pitchDitchID = 1; pitchDitchID < 4000; pitchDitchID++) { + if (this->pitchDitches[pitchDitchID].owner == 0) { + continue; + } + if (this->pitchDitches[pitchDitchID].owner == param_1) { + this->pitchDitches[pitchDitchID].owner = (short)param_2; + } else if (this->pitchDitches[pitchDitchID].owner == param_2) { + this->pitchDitches[pitchDitchID].owner = (short)param_1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 57a5f44ec..22c0f3948 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41463,7 +41463,7 @@ SHC_3BB0A8C1_0x00500850 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500890 | 0.0% | Pending -SHC_3BB0A8C1_0x00500940 | 0.0% | Pending +SHC_3BB0A8C1_0x00500940 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500980 | 0.0% | Pending From 7f4b7b393647c99972f1dff0388c5e5ce47b66d9 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:54 +0200 Subject: [PATCH 035/252] reimplement: SHC_3BB0A8C1_0x005006C0 100.00% Reimplemented --- .../TileMapState/clearInvalidMoatEntries.cpp | 37 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp b/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp new file mode 100644 index 000000000..62c1bcdf9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp @@ -0,0 +1,37 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005006C0 + void TileMapState::clearInvalidMoatEntries() + { + for (int moatID = 1; moatID < this->currentMoatCount; moatID++) { + if (this->moats[moatID].owner == 0) { + continue; + } + int tile = *(int*)&this->moats[moatID].tile; + if ((DAT_TileMapState::instance.LogicLayer[tile] & (L_MOAT_DUG_OR_PLANNED | L_MOAT)) != 0) { + continue; + } + if (this->BuildingLayer[tile] != 0) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatData, this)(moatID); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 22c0f3948..0693e757c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41447,7 +41447,7 @@ SHC_3BB0A8C1_0x00500640 | 0.0% | Pending SHC_3BB0A8C1_0x00500680 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005006C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005006C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500720 | 100.0% | Reimplemented From 00b1134572f1625fd33da29f831d436e67968b7c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:55 +0200 Subject: [PATCH 036/252] reimplement: SHC_3BB0A8C1_0x00500370 100.00% Reimplemented --- ...TileInSameAreaAndNoTooHeightDifference.cpp | 32 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/findTileInSameAreaAndNoTooHeightDifference.cpp diff --git a/src/OpenSHC/Map/TileMapState/findTileInSameAreaAndNoTooHeightDifference.cpp b/src/OpenSHC/Map/TileMapState/findTileInSameAreaAndNoTooHeightDifference.cpp new file mode 100644 index 000000000..061bb4f63 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/findTileInSameAreaAndNoTooHeightDifference.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500370 + BOOLEnum TileMapState::findTileInSameAreaAndNoTooHeightDifference(int area, int tile, int yUnk) + { + for (int attempts = 0; attempts < 8; attempts++) { + int neighbour = this->directionTranslationMatrix[yUnk][attempts] + tile; + if (this->HeightLayer[neighbour] > this->HeightLayer[tile] + 0x10) { + continue; + } + if ((short)this->PathConnectionLayer[neighbour] != area) { + continue; + } + return TRUE; + } + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0693e757c..2c4bdc0b2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41435,7 +41435,7 @@ SHC_3BB0A8C1_0x005002D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500310 | 0.0% | Pending -SHC_3BB0A8C1_0x00500370 | 0.0% | Pending +SHC_3BB0A8C1_0x00500370 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005003D0 | 0.0% | Pending From a41084a92771fcf814237164f6e500900cadd1bc Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:55 +0200 Subject: [PATCH 037/252] reimplement: SHC_3BB0A8C1_0x00500210 100.00% Reimplemented --- .../Map/TileMapState/getUnownedMoatCount.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getUnownedMoatCount.cpp diff --git a/src/OpenSHC/Map/TileMapState/getUnownedMoatCount.cpp b/src/OpenSHC/Map/TileMapState/getUnownedMoatCount.cpp new file mode 100644 index 000000000..4d1302890 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getUnownedMoatCount.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500210 + int TileMapState::getUnownedMoatCount() + { + int unownedMoatCount = 0; + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner == 0) { + unownedMoatCount++; + } + } + return unownedMoatCount; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2c4bdc0b2..d14b19fa4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41425,7 +41425,7 @@ SHC_3BB0A8C1_0x005000E0 | 0.0% | Pending SHC_3BB0A8C1_0x00500180 | 0.0% | Pending -SHC_3BB0A8C1_0x00500210 | 0.0% | Pending +SHC_3BB0A8C1_0x00500210 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500250 | 100.0% | Reimplemented From 8b14934480251ba002fbabcf348670970ca9427e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:55 +0200 Subject: [PATCH 038/252] reimplement: SHC_3BB0A8C1_0x004F80E0 100.00% Reimplemented --- .../increaseHeightForTunnelSingleTile.cpp | 53 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/increaseHeightForTunnelSingleTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelSingleTile.cpp b/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelSingleTile.cpp new file mode 100644 index 000000000..d9bdfab7e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelSingleTile.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F80E0 + void TileMapState::increaseHeightForTunnelSingleTile(int tile, uint x, uint y, int increment) + { + if ((this->LogicLayer[tile] + & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_RIVER | L_FORD | L_KEEP_NON_MANOR_HOUSE | L_MARSH | L_MOAT)) + != 0) { + return; + } + if ((this->LogicLayer[tile] & (L_SEA | L_BORDER | L_BORDER_EDGE | L_ROCKY)) != 0) { + return; + } + if (this->BuildingLayer[tile] != 0) { + return; + } + + if ((this->HeightLayer[tile] < 16 || this->DefaultHeightLayer[tile] < 16) + && (int)((uint)this->HeightLayer[tile] + increment) >= 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] + (char)increment; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(4, x, y); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d14b19fa4..ed766a0ab 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38787,7 +38787,7 @@ SHC_3BB0A8C1_0x004F80D4 | 0.0% | Pending SHC_3BB0A8C1_0x004F80D8 | 0.0% | Pending -SHC_3BB0A8C1_0x004F80E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F80E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F8160 | 0.0% | Pending From 811271f7416a4dbd5f1ffc88e4453c5d635b3c06 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:56 +0200 Subject: [PATCH 039/252] reimplement: SHC_3BB0A8C1_0x004F79D0 100.00% Reimplemented --- .../rebuildShowHiLayerFromHeights.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/rebuildShowHiLayerFromHeights.cpp diff --git a/src/OpenSHC/Map/TileMapState/rebuildShowHiLayerFromHeights.cpp b/src/OpenSHC/Map/TileMapState/rebuildShowHiLayerFromHeights.cpp new file mode 100644 index 000000000..a3183dde5 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/rebuildShowHiLayerFromHeights.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F79D0 + void TileMapState::rebuildShowHiLayerFromHeights() + { + for (int tile = 0; tile < 80400; tile += 8) { + this->ShowHiLayer[tile] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile]]; + this->ShowHiLayer[tile + 1] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 1]]; + this->ShowHiLayer[tile + 2] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 2]]; + this->ShowHiLayer[tile + 3] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 3]]; + this->ShowHiLayer[tile + 4] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 4]]; + this->ShowHiLayer[tile + 5] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 5]]; + this->ShowHiLayer[tile + 6] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 6]]; + this->ShowHiLayer[tile + 7] = (uchar)this->heightBasedScreenYOffset[this->HeightLayer[tile + 7]]; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ed766a0ab..f0d327287 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38767,7 +38767,7 @@ SHC_3BB0A8C1_0x004F7140 | 0.0% | Pending SHC_3BB0A8C1_0x004F7170 | 0.0% | Pending -SHC_3BB0A8C1_0x004F79D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F79D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F7A80 | 0.0% | Pending From 360822bebb45bdc5ff5051cdcd1346d1d24562fe Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:56 +0200 Subject: [PATCH 040/252] reimplement: SHC_3BB0A8C1_0x004FB970 36.92% ecx not kept across callee --- .../TileMapState/clearRockFootprintFlags.cpp | 36 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearRockFootprintFlags.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearRockFootprintFlags.cpp b/src/OpenSHC/Map/TileMapState/clearRockFootprintFlags.cpp new file mode 100644 index 000000000..57506b02c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearRockFootprintFlags.cpp @@ -0,0 +1,36 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_ROCKY; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB970 + void TileMapState::clearRockFootprintFlags(int rockID) + { + short rockX = DAT_LandscapeState::instance.rocks[rockID].x; + short rockY = DAT_LandscapeState::instance.rocks[rockID].y; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, DAT_LandscapeState::instance.rocks[rockID].size); + buildingSizeTileIndex++; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + rockY].addXgetTile + + this->buildingX + rockX; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->OrganismLayer[tile] = 0; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f0d327287..9c1534c1b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40577,7 +40577,7 @@ SHC_3BB0A8C1_0x004FB7D0 | 0.0% | Pending SHC_3BB0A8C1_0x004FB8E0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FB970 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB970 | 36.9% | ecx not kept across callee SHC_3BB0A8C1_0x004FB990 | 0.0% | Pending From 9c433d55f5a345a3f780dd766b5fe9e4ce45b746 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:56 +0200 Subject: [PATCH 041/252] reimplement: SHC_3BB0A8C1_0x00500890 100.00% Reimplemented --- .../Map/TileMapState/destroyPitchDitch.cpp | 41 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/destroyPitchDitch.cpp diff --git a/src/OpenSHC/Map/TileMapState/destroyPitchDitch.cpp b/src/OpenSHC/Map/TileMapState/destroyPitchDitch.cpp new file mode 100644 index 000000000..0773ecc90 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/destroyPitchDitch.cpp @@ -0,0 +1,41 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500890 + void TileMapState::destroyPitchDitch(int pitchDitchID) + { + this->LogicLayer[this->pitchDitches[pitchDitchID].tile] + = this->LogicLayer[this->pitchDitches[pitchDitchID].tile] & ~L_PLAIN2_AND_PITCH; + this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] + = this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] & 0xdfff; + this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] + = this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] & 0xbfff; + if ((this->LogicLayer[this->pitchDitches[pitchDitchID].tile] & L_WALL_OR_GATEHOUSE) == 0 + && this->BuildingLayer[this->pitchDitches[pitchDitchID].tile] == 0) { + this->HeightLayer[this->pitchDitches[pitchDitchID].tile] + = this->DefaultHeightLayer[this->pitchDitches[pitchDitchID].tile]; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(4, this->pitchDitches[pitchDitchID].x, this->pitchDitches[pitchDitchID].y); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(PitchDitch), 0, &this->pitchDitches[pitchDitchID]); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9c1534c1b..79d00953b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41461,7 +41461,7 @@ SHC_3BB0A8C1_0x00500800 | 0.0% | Pending SHC_3BB0A8C1_0x00500850 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500890 | 0.0% | Pending +SHC_3BB0A8C1_0x00500890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500940 | 100.0% | Reimplemented From 3048516d7f4e2e3c5a104965de1c9790c4bc3d0f Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 00:49:57 +0200 Subject: [PATCH 042/252] reimplement: SHC_3BB0A8C1_0x004F9880 100.00% Reimplemented --- .../getBuildingSizeIndexMappingData.cpp | 41 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getBuildingSizeIndexMappingData.cpp diff --git a/src/OpenSHC/Map/TileMapState/getBuildingSizeIndexMappingData.cpp b/src/OpenSHC/Map/TileMapState/getBuildingSizeIndexMappingData.cpp new file mode 100644 index 000000000..1ed38d438 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getBuildingSizeIndexMappingData.cpp @@ -0,0 +1,41 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingSizeIndexMapping.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9880 + void TileMapState::getBuildingSizeIndexMappingData(int buildingSizeTileIndex, int buildingWidthOrHeight) + { + this->constructionTileCount = buildingWidthOrHeight * buildingWidthOrHeight; + this->buildingX = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][0]; + this->buildingY = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][1]; + switch (this->mapOrientation) { + case 0: + this->buildingRotationRelatedValue + = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][2]; + return; + case 2: + this->buildingRotationRelatedValue + = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][3]; + return; + case 4: + this->buildingRotationRelatedValue + = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][4]; + return; + case 6: + this->buildingRotationRelatedValue + = DAT_BuildingSizeIndexMapping::instance[buildingWidthOrHeight][buildingSizeTileIndex][5]; + } + return; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 79d00953b..0cf7f5e43 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39391,7 +39391,7 @@ SHC_3BB0A8C1_0x004F9590 | 0.0% | Pending SHC_3BB0A8C1_0x004F9630 | 0.0% | Pending -SHC_3BB0A8C1_0x004F9880 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9880 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F990C | 0.0% | Pending From 11bdaa629d317cc15f61a0ef32b76bbcf9545435 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:27 +0200 Subject: [PATCH 043/252] reimplement: SHC_3BB0A8C1_0x00502950 100.00% Reimplemented --- .../getMaxWallHeightInBrushArea.cpp | 43 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getMaxWallHeightInBrushArea.cpp diff --git a/src/OpenSHC/Map/TileMapState/getMaxWallHeightInBrushArea.cpp b/src/OpenSHC/Map/TileMapState/getMaxWallHeightInBrushArea.cpp new file mode 100644 index 000000000..180917435 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getMaxWallHeightInBrushArea.cpp @@ -0,0 +1,43 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00502950 + int TileMapState::getMaxWallHeightInBrushArea(int param_1, uint param_2) + { + int baseTile = param_1; + uint baseY = param_2; + int maxWallHeight = 0; + for (int index = 1; index < 5; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, ¶m_1, (int*)¶m_2, baseTile, baseY); + if ((this->LogicLayer[param_1] & L_WALL_OR_GATEHOUSE) == 0) { + continue; + } + if ((this->LogicLayer[param_1] & L_STOCKPILEUnk) != 0) { + continue; + } + if ((this->LogicLayer[param_1] & L_CRENEL) != 0) { + continue; + } + if (this->HeightLayer[param_1] > maxWallHeight) { + maxWallHeight = this->HeightLayer[param_1]; + } + } + return maxWallHeight; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0cf7f5e43..09d8ed989 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41577,7 +41577,7 @@ SHC_3BB0A8C1_0x005024F0 | 0.0% | Pending SHC_3BB0A8C1_0x00502680 | 0.0% | Pending -SHC_3BB0A8C1_0x00502950 | 0.0% | Pending +SHC_3BB0A8C1_0x00502950 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005029D0 | 0.0% | Pending From 69605d9fcee80789c4efea0ae4c63714d4034c2a Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:27 +0200 Subject: [PATCH 044/252] reimplement: SHC_3BB0A8C1_0x00500640 46.15% ecx not kept across callee --- .../updateMoatCountdownTimers.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateMoatCountdownTimers.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateMoatCountdownTimers.cpp b/src/OpenSHC/Map/TileMapState/updateMoatCountdownTimers.cpp new file mode 100644 index 000000000..721fa3f16 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateMoatCountdownTimers.cpp @@ -0,0 +1,25 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500640 + void TileMapState::updateMoatCountdownTimers() + { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::recountTotalOwnedMoats, this)(); + for (int moatID = 0; moatID < this->currentMoatCount; moatID++) { + if (this->moats[moatID].owner != 0 && this->moats[moatID].someCountDown > 0) { + this->moats[moatID].someCountDown = this->moats[moatID].someCountDown - 1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 09d8ed989..f6e31f854 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41443,7 +41443,7 @@ SHC_3BB0A8C1_0x00500500 | 0.0% | Pending SHC_3BB0A8C1_0x005005F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500640 | 0.0% | Pending +SHC_3BB0A8C1_0x00500640 | 46.1% | ecx not kept across callee SHC_3BB0A8C1_0x00500680 | 100.0% | Reimplemented From 79f303eef9ddc9aeb3224026ba1701f61ec7101d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:27 +0200 Subject: [PATCH 045/252] reimplement: SHC_3BB0A8C1_0x00500310 100.00% Reimplemented --- .../Map/TileMapState/clearMoatDataAtTile.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp b/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp new file mode 100644 index 000000000..060852b40 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500310 + void TileMapState::clearMoatDataAtTile(int x, int y) + { + for (int moatID = 0; moatID < this->currentMoatCount; moatID++) { + if ((short)this->moats[moatID].x == x && (short)this->moats[moatID].y == y) { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(Moat), 0, &this->moats[moatID]); + this->moatTileCount = this->moatTileCount - 1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f6e31f854..b45ad28f6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41433,7 +41433,7 @@ SHC_3BB0A8C1_0x00500290 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005002D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500310 | 0.0% | Pending +SHC_3BB0A8C1_0x00500310 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500370 | 100.0% | Reimplemented From 019402e08e506c2d9fd5f97b689afd608d3d1127 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:28 +0200 Subject: [PATCH 046/252] reimplement: SHC_3BB0A8C1_0x00500180 100.00% Reimplemented --- .../countUnfinishedMoatTilesForPlayer.cpp | 28 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp b/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp new file mode 100644 index 000000000..ba8a2bd30 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500180 + int TileMapState::countUnfinishedMoatTilesForPlayer(int playerID) + { + int unfinishedMoatTiles = 0; + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner != 0 && this->moats[moatID].owner == playerID + && (this->LogicLayer[*(int*)&this->moats[moatID].tile] & L_MOAT) == 0) { + unfinishedMoatTiles++; + } + } + return unfinishedMoatTiles; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b45ad28f6..7084e29e7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41423,7 +41423,7 @@ SHC_3BB0A8C1_0x005000A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005000E0 | 0.0% | Pending -SHC_3BB0A8C1_0x00500180 | 0.0% | Pending +SHC_3BB0A8C1_0x00500180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500210 | 100.0% | Reimplemented From aaf5c4352f3cfdb1336598dd617c73e6e69b5c81 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:28 +0200 Subject: [PATCH 047/252] reimplement: SHC_3BB0A8C1_0x00514480 40.00% logic masks merged by cl --- src/OpenSHC/Map/TileMapState/planMoat.cpp | 68 +++++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/planMoat.cpp diff --git a/src/OpenSHC/Map/TileMapState/planMoat.cpp b/src/OpenSHC/Map/TileMapState/planMoat.cpp new file mode 100644 index 000000000..212b5b45c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/planMoat.cpp @@ -0,0 +1,68 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00514480 + void TileMapState::planMoat(undefined4 playerID, int tile, uint tileY) + { + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BORDER | L_BORDER_EDGE)) != 0) { + return; + } + if (this->OrganismLayer[tile] != 0) { + return; + } + if ((logic & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0) { + return; + } + if (this->BuildingLayer[tile] != 0) { + return; + } + if ((logic & (L_WALL_OR_GATEHOUSE | L_BOULDERS | L_IRON | L_RIVER | L_FORD | L_MARSH)) != 0) { + return; + } + if ((logic & (L_SEA | L_PLAIN1_AND_FARM | L_ROCKY)) != 0) { + return; + } + + if ((logic & (L_MOAT_DUG_OR_PLANNED | L_MOAT)) == 0 && this->HeightLayer[tile] <= 0xc) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::createMoatData, this)( + playerID, tile - DAT_ViewportRenderState::instance.translationMatrix[tileY].addXgetTile, tileY, 0) + != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_MOAT_DUG_OR_PLANNED; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(tileY, tile); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7084e29e7..5a33d1074 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44743,7 +44743,7 @@ SHC_3BB0A8C1_0x00512920 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00512940 | 0.0% | Pending -SHC_3BB0A8C1_0x00514480 | 0.0% | Pending +SHC_3BB0A8C1_0x00514480 | 40.0% | logic masks merged by cl SHC_3BB0A8C1_0x00514520 | 0.0% | Pending From 1b17bc37e865116f77e0bc2f62778f64daaa1a48 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:28 +0200 Subject: [PATCH 048/252] reimplement: SHC_3BB0A8C1_0x00511850 58.82% ecx not kept across callee --- .../TileMapState/updateGameRelatedValue.cpp | 43 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateGameRelatedValue.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateGameRelatedValue.cpp b/src/OpenSHC/Map/TileMapState/updateGameRelatedValue.cpp new file mode 100644 index 000000000..05a9f946f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateGameRelatedValue.cpp @@ -0,0 +1,43 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00511850 + void TileMapState::updateGameRelatedValue() + { + if (DAT_GameState::instance.mapAndTime.gameEventRelatedCountdown == 0) { + return; + } + + if (DAT_GameState::instance.mapAndTime.gameEventRelatedCountdown == 0x28) { + this->field187_0x554a10 = -1; + } + DAT_GameState::instance.mapAndTime.gameEventRelatedCountdown + = DAT_GameState::instance.mapAndTime.gameEventRelatedCountdown - 1; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setSignpostDistanceForCampaignMission, this)(); + int signpostDistance = ((0x28 - DAT_GameState::instance.mapAndTime.gameEventRelatedCountdown) + * DAT_GameState::instance.mapAndTime.unk_signpostDistance) + / 0x28; + if (signpostDistance == this->field187_0x554a10) { + return; + } + + this->field187_0x554a10 = signpostDistance; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingUpdate_0x4a8ab0, + DAT_PathFindingState::ptr)(signpostDistance); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5a33d1074..801db4f82 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44189,7 +44189,7 @@ SHC_3BB0A8C1_0x005115C0 | 0.0% | Pending SHC_3BB0A8C1_0x005116E0 | 0.0% | Pending -SHC_3BB0A8C1_0x00511850 | 0.0% | Pending +SHC_3BB0A8C1_0x00511850 | 58.8% | ecx not kept across callee SHC_3BB0A8C1_0x005118C0 | 0.0% | Pending From fb3a0c057239b4b7ae5e5cf606055424f442127e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:29 +0200 Subject: [PATCH 049/252] reimplement: SHC_3BB0A8C1_0x00500B50 68.35% loop guard/regalloc differs --- .../computeTileAlongAxisOffset.cpp | 33 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/computeTileAlongAxisOffset.cpp diff --git a/src/OpenSHC/Map/TileMapState/computeTileAlongAxisOffset.cpp b/src/OpenSHC/Map/TileMapState/computeTileAlongAxisOffset.cpp new file mode 100644 index 000000000..545ad94f3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/computeTileAlongAxisOffset.cpp @@ -0,0 +1,33 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500B50 + int TileMapState::computeTileAlongAxisOffset(int tile, int addend, uint offset) + { + int yStep = 1; + int direction = 4; + if ((int)offset < 0) { + yStep = -1; + direction = 0; + } + + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + for (int remaining = abs((int)offset); remaining > 0; remaining--) { + tile = tile + this->directionTranslationMatrix[y][direction]; + y = y + yStep; + } + return tile + addend; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 801db4f82..df0b6cc33 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41467,7 +41467,7 @@ SHC_3BB0A8C1_0x00500940 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500980 | 0.0% | Pending -SHC_3BB0A8C1_0x00500B50 | 0.0% | Pending +SHC_3BB0A8C1_0x00500B50 | 68.3% | loop guard/regalloc differs SHC_3BB0A8C1_0x00500BB0 | 0.0% | Pending From 0b6dca69eb6210987deb6491a3185b14519b444c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:29 +0200 Subject: [PATCH 050/252] reimplement: SHC_3BB0A8C1_0x004F85B0 41.03% regalloc: extra edi --- .../isTileEnclosedByWallsOrGates.cpp | 42 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isTileEnclosedByWallsOrGates.cpp diff --git a/src/OpenSHC/Map/TileMapState/isTileEnclosedByWallsOrGates.cpp b/src/OpenSHC/Map/TileMapState/isTileEnclosedByWallsOrGates.cpp new file mode 100644 index 000000000..401f7133c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isTileEnclosedByWallsOrGates.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F85B0 + BOOLEnum TileMapState::isTileEnclosedByWallsOrGates(int tile, int y) + { + if ((this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & (L_STOCKPILEUnk | L_CRENEL)) == 0) { + return TRUE; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & (L_STOCKPILEUnk | L_CRENEL)) == 0) { + return TRUE; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & (L_STOCKPILEUnk | L_CRENEL)) == 0) { + return TRUE; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & (L_STOCKPILEUnk | L_CRENEL)) == 0) { + return TRUE; + } + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index df0b6cc33..6fcd7da8a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39357,7 +39357,7 @@ SHC_3BB0A8C1_0x004F8524 | 0.0% | Pending SHC_3BB0A8C1_0x004F8530 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F85B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F85B0 | 41.0% | regalloc: extra edi SHC_3BB0A8C1_0x004F8640 | 40.0% | regalloc: extra edi From 4f210adb4294565d37c20e1eff2254bbd7e09729 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:29 +0200 Subject: [PATCH 051/252] reimplement: SHC_3BB0A8C1_0x004FAA30 91.89% Style pass, asm differs --- .../updateAreaBasedOnSurrounding.cpp | 37 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateAreaBasedOnSurrounding.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateAreaBasedOnSurrounding.cpp b/src/OpenSHC/Map/TileMapState/updateAreaBasedOnSurrounding.cpp new file mode 100644 index 000000000..ad57f242c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateAreaBasedOnSurrounding.cpp @@ -0,0 +1,37 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAA30 + void TileMapState::updateAreaBasedOnSurrounding(int x, int y, int buildingSize) + { + int area + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findAccessibleAreaNearBuildingLocation, + DAT_BuildingsState::ptr)(x, y, buildingSize); + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, buildingSize); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if (this->PathConnectionLayer[tile] == 0) { + this->PathConnectionLayer[tile] = (ushort)area; + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6fcd7da8a..3bdec4aa8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40349,7 +40349,7 @@ SHC_3BB0A8C1_0x004FA8D0 | 0.0% | Pending SHC_3BB0A8C1_0x004FA9D0 | 43.6% | ecx not kept across callee -SHC_3BB0A8C1_0x004FAA30 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAA30 | 91.9% | Style pass, asm differs SHC_3BB0A8C1_0x004FAAB0 | 0.0% | Pending From 543ec25975bb255153e00792162178a5a97357ae Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:30 +0200 Subject: [PATCH 052/252] reimplement: SHC_3BB0A8C1_0x00508870 88.89% Style pass, asm differs --- .../Map/TileMapState/clearDrawBridgeWater.cpp | 42 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearDrawBridgeWater.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearDrawBridgeWater.cpp b/src/OpenSHC/Map/TileMapState/clearDrawBridgeWater.cpp new file mode 100644 index 000000000..fafa2f2c0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearDrawBridgeWater.cpp @@ -0,0 +1,42 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508870 + void TileMapState::clearDrawBridgeWater(int x, int y) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 5); + int targetedTile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] & ~L_MOAT; + this->HeightLayer[targetedTile] = 8; + uint moatID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(targetedTile); + if (moatID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatData, this)(moatID); + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] & ~L_MOAT; + this->BuildingWasLayer[targetedTile] = 0; + } + this->BuildingLayer[targetedTile] = 0; + buildingSizeTileIndex++; + this->BuildingWasLayer[targetedTile] = 0; + this->ChangedLayer[targetedTile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3bdec4aa8..a5a3118d2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42161,7 +42161,7 @@ SHC_3BB0A8C1_0x00508590 | 0.0% | Pending SHC_3BB0A8C1_0x00508760 | 0.0% | Pending -SHC_3BB0A8C1_0x00508870 | 0.0% | Pending +SHC_3BB0A8C1_0x00508870 | 88.9% | Style pass, asm differs SHC_3BB0A8C1_0x00508910 | 0.0% | Pending From 824dde313c50c30d10a50008ad6b72e673bdbbd0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:30 +0200 Subject: [PATCH 053/252] reimplement: SHC_3BB0A8C1_0x004FB8E0 28.17% ecx not kept across callee --- .../TileMapState/clearTreeFootprintFlags.cpp | 39 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearTreeFootprintFlags.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearTreeFootprintFlags.cpp b/src/OpenSHC/Map/TileMapState/clearTreeFootprintFlags.cpp new file mode 100644 index 000000000..c59926a93 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearTreeFootprintFlags.cpp @@ -0,0 +1,39 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB8E0 + void TileMapState::clearTreeFootprintFlags(int treeID) + { + short treeX = DAT_LandscapeState::instance.trees[treeID].xPosition; + short treeY = DAT_LandscapeState::instance.trees[treeID].yPosition; + this->OrganismLayer[DAT_LandscapeState::instance.trees[treeID].tile] = 0; + this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] + = this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] & ~L_TREE; + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + index, DAT_LandscapeState::instance.trees[treeID].size); + index++; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + treeY].addXgetTile + treeX + + this->buildingX; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_TREE_VARIATION; + } while (index < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a5a3118d2..307cf89ac 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40575,7 +40575,7 @@ SHC_3BB0A8C1_0x004FB770 | 0.0% | Pending SHC_3BB0A8C1_0x004FB7D0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FB8E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB8E0 | 28.2% | ecx not kept across callee SHC_3BB0A8C1_0x004FB970 | 36.9% | ecx not kept across callee From b61279de8a314dd45ee0e626ec51b3a58dcfcca1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:30 +0200 Subject: [PATCH 054/252] reimplement: SHC_3BB0A8C1_0x004FC280 85.19% XYPair base regalloc --- .../propagateCliffEdgeFlagFromNeighbor.cpp | 54 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/propagateCliffEdgeFlagFromNeighbor.cpp diff --git a/src/OpenSHC/Map/TileMapState/propagateCliffEdgeFlagFromNeighbor.cpp b/src/OpenSHC/Map/TileMapState/propagateCliffEdgeFlagFromNeighbor.cpp new file mode 100644 index 000000000..0f82ec6bd --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/propagateCliffEdgeFlagFromNeighbor.cpp @@ -0,0 +1,54 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_STONES_OR_DRIVEN_SANDUnk; + using OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + using OpenSHC::Map::LogicHelpers::L_RIVER; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC280 + void TileMapState::propagateCliffEdgeFlagFromNeighbor(int tile, int x, int y) + { + int height = this->HeightLayer[tile]; + if (this->Logic2Layer[tile] != 0) { + return; + } + + for (int index = 0; index < 8; index++) { + uint neighbourY = DAT_TerrainDefinedData::instance.field2476_0x372c[index].y + y; + uint neighbourX = DAT_TerrainDefinedData::instance.field2476_0x372c[index].x + x; + if (neighbourX > 399 || neighbourY > 399) { + continue; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + neighbourX] == 0) { + continue; + } + int neighbour = DAT_ViewportRenderState::instance.translationMatrix[neighbourY].addXgetTile + + DAT_TerrainDefinedData::instance.field2476_0x372c[index].x + x; + if ((this->LogicLayer[neighbour] & L_RIVER) == 0) { + continue; + } + if ((this->Logic2Layer[neighbour] & (L2_OASIS_GRASS | L2_STONES_OR_DRIVEN_SANDUnk)) == 0) { + continue; + } + if (this->HeightLayer[neighbour] < height) { + continue; + } + this->Logic2Layer[tile] = L2_THICK_SCRUB; + return; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 307cf89ac..7a8a7bfe5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41083,7 +41083,7 @@ SHC_3BB0A8C1_0x004FBE70 | 0.0% | Pending SHC_3BB0A8C1_0x004FC0B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FC280 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC280 | 85.2% | XYPair base regalloc SHC_3BB0A8C1_0x004FC340 | 0.0% | Pending From c3af393257bcb7098fc1f5c38fb14a4eeed0bb81 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:31 +0200 Subject: [PATCH 055/252] reimplement: SHC_3BB0A8C1_0x004FAE50 35.14% ecx not kept across callee --- .../clearFixedSizeTwoBuildingFootprint.cpp | 49 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearFixedSizeTwoBuildingFootprint.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearFixedSizeTwoBuildingFootprint.cpp b/src/OpenSHC/Map/TileMapState/clearFixedSizeTwoBuildingFootprint.cpp new file mode 100644 index 000000000..8576b2d97 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearFixedSizeTwoBuildingFootprint.cpp @@ -0,0 +1,49 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAE50 + void TileMapState::clearFixedSizeTwoBuildingFootprint(int x, int y) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 2); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE | L_CRENEL | L_BUILDING | L_STAIRS | L_CRENEL_VARIATIONUnk + | L_KEEP_NON_MANOR_HOUSE); + short buildingID = this->BuildingLayer[tile]; + this->BuildingLayer[tile] = 0; + if (DAT_BuildingsState::instance.buildings[buildingID].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } + buildingSizeTileIndex++; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7a8a7bfe5..bb88dbb31 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40363,7 +40363,7 @@ SHC_3BB0A8C1_0x004FAD20 | 45.3% | ecx not kept across callee SHC_3BB0A8C1_0x004FAD70 | 0.0% | Pending -SHC_3BB0A8C1_0x004FAE50 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAE50 | 35.1% | ecx not kept across callee SHC_3BB0A8C1_0x004FAEE0 | 0.0% | Pending From 053c6ac5c58b86a13a87407a5cc4e6ab86d42676 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:04:31 +0200 Subject: [PATCH 056/252] reimplement: SHC_3BB0A8C1_0x004F8B50 100.00% Reimplemented --- ...tOrientationThatIsWallTowerOrGatehouse.cpp | 42 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getOrientationThatIsWallTowerOrGatehouse.cpp diff --git a/src/OpenSHC/Map/TileMapState/getOrientationThatIsWallTowerOrGatehouse.cpp b/src/OpenSHC/Map/TileMapState/getOrientationThatIsWallTowerOrGatehouse.cpp new file mode 100644 index 000000000..8a13583f2 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getOrientationThatIsWallTowerOrGatehouse.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8B50 + int TileMapState::getOrientationThatIsWallTowerOrGatehouse(uint x, uint y) + { + if (x > 399 || y > 399) { + return 0xf; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0xf; + } + + int rowTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + for (int index = 0; index < 8; index++) { + int orientation = DAT_TerrainDefinedData::instance.SomeOrientationOrderArray[index]; + int neighbour = this->directionTranslationMatrix[y][orientation] + rowTile; + if ((this->LogicLayer[neighbour] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[neighbour] & (L_STOCKPILEUnk | L_CRENEL_VARIATIONUnk)) == 0) { + return orientation; + } + } + return 0xf; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bb88dbb31..847a0f686 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39375,7 +39375,7 @@ SHC_3BB0A8C1_0x004F8A40 | 0.0% | Pending SHC_3BB0A8C1_0x004F8AC0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8B50 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8B50 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F8BD0 | 0.0% | Pending From 8eedb255703a6bbf1e0fc2a6ce0514045bc95c94 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:14:46 +0200 Subject: [PATCH 057/252] types: Moat.tile is a 32-bit field, x/y are signed The original reads Moat+0x00 with 32-bit compares (e.g. 0x00500250 returnOwnedMoatAtTile, 0x00500290 returnMoatIDForPlayerIDs, 0x00500180 countUnfinishedMoatTilesForPlayer all do `cmp dword ptr [ecx], reg`), so `ushort tile` plus explicit `padding_0x2[2]` is really one `int tile`. x and y are read with movsx and compared against signed ints, so they are `short` rather than `undefined2`. This removes the `*(int*)&...tile` and `(short)` casts the reimplementations needed to match; all five affected functions stay at 100%. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/Moat.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/Map/Moat.hpp b/src/OpenSHC/Map/Moat.hpp index a676966a9..1d35bbf0e 100644 --- a/src/OpenSHC/Map/Moat.hpp +++ b/src/OpenSHC/Map/Moat.hpp @@ -15,10 +15,9 @@ namespace Map { // SIZE: 0x00000010 typedef struct Moat { - ushort tile; // 0x00000000 length: 2 - undefined1 padding_0x2[2]; // 0x00000002 length: 2 - undefined2 x; // 0x00000004 length: 2 - undefined2 y; // 0x00000006 length: 2 + int tile; // 0x00000000 length: 4 + short x; // 0x00000004 length: 2 + short y; // 0x00000006 length: 2 short zeroOrTwo; // 0x00000008 length: 2 undefined1 padding_0xa[2]; // 0x0000000A length: 2 char owner; // 0x0000000C length: 1 From 84b7a6fd9dd2d4b2a5115c871eb4b5d0624c2228 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:15:09 +0200 Subject: [PATCH 058/252] reimplement: SHC_3BB0A8C1_0x005006C0 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp b/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp index 62c1bcdf9..b0a7f46b2 100644 --- a/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp +++ b/src/OpenSHC/Map/TileMapState/clearInvalidMoatEntries.cpp @@ -22,7 +22,7 @@ namespace Map { if (this->moats[moatID].owner == 0) { continue; } - int tile = *(int*)&this->moats[moatID].tile; + int tile = this->moats[moatID].tile; if ((DAT_TileMapState::instance.LogicLayer[tile] & (L_MOAT_DUG_OR_PLANNED | L_MOAT)) != 0) { continue; } From 652e5bc92362401fa7960e6ba88ad458bcc650b2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:15:09 +0200 Subject: [PATCH 059/252] reimplement: SHC_3BB0A8C1_0x00500180 100.00% Reimplemented --- .../Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp b/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp index ba8a2bd30..571fdbf2c 100644 --- a/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp +++ b/src/OpenSHC/Map/TileMapState/countUnfinishedMoatTilesForPlayer.cpp @@ -17,7 +17,7 @@ namespace Map { int unfinishedMoatTiles = 0; for (int moatID = 1; moatID < 16000; moatID++) { if (this->moats[moatID].owner != 0 && this->moats[moatID].owner == playerID - && (this->LogicLayer[*(int*)&this->moats[moatID].tile] & L_MOAT) == 0) { + && (this->LogicLayer[this->moats[moatID].tile] & L_MOAT) == 0) { unfinishedMoatTiles++; } } From 6e28ea665be6302eae1e0669aefb100e81a169de Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:15:09 +0200 Subject: [PATCH 060/252] reimplement: SHC_3BB0A8C1_0x00500290 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp b/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp index be9576c69..797027058 100644 --- a/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp +++ b/src/OpenSHC/Map/TileMapState/returnMoatIDForPlayerIDs.cpp @@ -13,7 +13,7 @@ namespace Map { int TileMapState::returnMoatIDForPlayerIDs(int playerID, int playerID2) { for (int moatID = 1; moatID < this->currentMoatCount; moatID++) { - if (*(int*)&this->moats[moatID].tile == playerID && this->moats[moatID].owner == playerID2) { + if (this->moats[moatID].tile == playerID && this->moats[moatID].owner == playerID2) { return moatID; } } From 817b390fe4d6844a29d4d9a1b39e469addaf05f1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:15:09 +0200 Subject: [PATCH 061/252] reimplement: SHC_3BB0A8C1_0x00500250 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp b/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp index e66161e43..5174adaec 100644 --- a/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp +++ b/src/OpenSHC/Map/TileMapState/returnOwnedMoatAtTile.cpp @@ -13,7 +13,7 @@ namespace Map { int TileMapState::returnOwnedMoatAtTile(int targetedTile) { for (int moatID = 1; moatID < this->currentMoatCount; moatID++) { - if (this->moats[moatID].owner != 0 && *(int*)&this->moats[moatID].tile == targetedTile) { + if (this->moats[moatID].owner != 0 && this->moats[moatID].tile == targetedTile) { return moatID; } } From cd98c8f8c7be55f343e72fd15a39e6ddfbe38fbe Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:15:10 +0200 Subject: [PATCH 062/252] reimplement: SHC_3BB0A8C1_0x00500310 100.00% Reimplemented --- src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp b/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp index 060852b40..f7282fa57 100644 --- a/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp +++ b/src/OpenSHC/Map/TileMapState/clearMoatDataAtTile.cpp @@ -16,7 +16,7 @@ namespace Map { void TileMapState::clearMoatDataAtTile(int x, int y) { for (int moatID = 0; moatID < this->currentMoatCount; moatID++) { - if ((short)this->moats[moatID].x == x && (short)this->moats[moatID].y == y) { + if (this->moats[moatID].x == x && this->moats[moatID].y == y) { MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( sizeof(Moat), 0, &this->moats[moatID]); this->moatTileCount = this->moatTileCount - 1; From d2a6415b9e122357f0116ec25ab649430782a07c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:19:56 +0200 Subject: [PATCH 063/252] types: Building.x/y are signed, tileRef1..36 is one int[36] x and y at 0xEE/0xF0 are read with movsx and compared against signed ints (e.g. 0x004FB360 clearBuildingDisplayFlagsAndEntities, 0x004FAEE0 isUnitBlockingSizeFiveFootprint), so they are `short`, not `ushort`. tileRef1..tileRef36 at 0x1C8..0x254 are one contiguous int[36]: 0x00507060 stampBuildingOntoTileMap indexes it as an array (`*(int*)(workers + i*2 + 8) = tile` for i < 36, i.e. 0x1C8 + i*4), which needed a pointer cast to express against the split fields. The tileRefN -> tileRefs[N-1] renames in the TileMapState sources are mechanical and forced by the header change. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/Buildings/Building.hpp | 41 +--- .../clearBuildingTilesAndTrees.cpp | 58 ++++++ .../Map/TileMapState/placeApplefarm.cpp | 132 +++++++++++++ .../Map/TileMapState/placeBarracks.cpp | 182 ++++++++++++++++++ .../Map/TileMapState/placeDairyfarm.cpp | 126 ++++++++++++ .../Map/TileMapState/placeDrawbridge.cpp | 68 +++++++ .../Map/TileMapState/placeEngineersguild.cpp | 99 ++++++++++ src/OpenSHC/Map/TileMapState/placeHopfarm.cpp | 136 +++++++++++++ .../Map/TileMapState/placeTunnelersguild.cpp | 99 ++++++++++ .../Map/TileMapState/placeWheatfarm.cpp | 120 ++++++++++++ 10 files changed, 1023 insertions(+), 38 deletions(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingTilesAndTrees.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeApplefarm.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeBarracks.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeDairyfarm.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeDrawbridge.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeEngineersguild.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeHopfarm.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeTunnelersguild.cpp create mode 100644 src/OpenSHC/Map/TileMapState/placeWheatfarm.cpp diff --git a/src/OpenSHC/Map/Buildings/Building.hpp b/src/OpenSHC/Map/Buildings/Building.hpp index c2e44eaa5..6614308bb 100644 --- a/src/OpenSHC/Map/Buildings/Building.hpp +++ b/src/OpenSHC/Map/Buildings/Building.hpp @@ -99,8 +99,8 @@ namespace Map { ushort microX; // 0x000000E8 length: 2 ushort microY; // 0x000000EA length: 2 short terrainHeightUnk; // 0x000000EC length: 2 - ushort x; // 0x000000EE length: 2 - ushort y; // 0x000000F0 length: 2 + short x; // 0x000000EE length: 2 + short y; // 0x000000F0 length: 2 undefined1 padding_0xf2[2]; // 0x000000F2 length: 2 uint currentTilePositionAdjusted; // 0x000000F4 length: 4 uint widthOrHeight; // 0x000000F8 length: 4 @@ -140,42 +140,7 @@ namespace Map { short field138_0x1c2; // 0x000001C2 length: 2 short growCounter; // 0x000001C4 length: 2 undefined1 padding_0x1c6[2]; // 0x000001C6 length: 2 - int tileRef1; // 0x000001C8 length: 4 - int tileRef2; // 0x000001CC length: 4 - int tileRef3; // 0x000001D0 length: 4 - int tileRef4; // 0x000001D4 length: 4 - int tileRef5; // 0x000001D8 length: 4 - int tileRef6; // 0x000001DC length: 4 - int tileRef7; // 0x000001E0 length: 4 - int tileRef8; // 0x000001E4 length: 4 - int tileRef9; // 0x000001E8 length: 4 - int tileRef10; // 0x000001EC length: 4 - int tileRef11; // 0x000001F0 length: 4 - int tileRef12; // 0x000001F4 length: 4 - int tileRef13; // 0x000001F8 length: 4 - int tileRef14; // 0x000001FC length: 4 - int tileRef15; // 0x00000200 length: 4 - int tileRef16; // 0x00000204 length: 4 - int tileRef17; // 0x00000208 length: 4 - int tileRef18; // 0x0000020C length: 4 - int tileRef19; // 0x00000210 length: 4 - int tileRef20; // 0x00000214 length: 4 - int tileRef21; // 0x00000218 length: 4 - int tileRef22; // 0x0000021C length: 4 - int tileRef23; // 0x00000220 length: 4 - int tileRef24; // 0x00000224 length: 4 - int tileRef25; // 0x00000228 length: 4 - int tileRef26; // 0x0000022C length: 4 - int tileRef27; // 0x00000230 length: 4 - int tileRef28; // 0x00000234 length: 4 - int tileRef29; // 0x00000238 length: 4 - int tileRef30; // 0x0000023C length: 4 - int tileRef31; // 0x00000240 length: 4 - int tileRef32; // 0x00000244 length: 4 - int tileRef33; // 0x00000248 length: 4 - int tileRef34; // 0x0000024C length: 4 - int tileRef35; // 0x00000250 length: 4 - int tileRef36; // 0x00000254 length: 4 + int tileRefs[36]; // 0x000001C8 length: 144 undefined1 wheatGrowStateRelated; // 0x00000258 length: 1 undefined1 padding_0x259[3]; // 0x00000259 length: 3 int tunnelerCounter; // 0x0000025C length: 4 diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingTilesAndTrees.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingTilesAndTrees.cpp new file mode 100644 index 000000000..e6e731787 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingTilesAndTrees.cpp @@ -0,0 +1,58 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAAB0 + void TileMapState::clearBuildingTilesAndTrees(int buildingID, int surfaceArea) + { + int _treeID; + Building* _pTileRef; + int _tile; + if (0 < surfaceArea) { + _pTileRef = &DAT_BuildingsState::instance.buildings[buildingID]; + do { + _tile = _pTileRef->tileRefs[0]; + if ((((this->LogicLayer[_tile] & L_FARM_FIELD_APPLE) != 0) + && (_treeID = (int)this->OrganismLayer[_tile], _treeID != 0)) + && (_treeID < 2000)) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(_treeID); + } + this->LogicLayer[_tile] = this->LogicLayer[_tile] + & ~(L_BUILDING | L_FARM_FIELD_WHEAT | L_FARM_FIELD_HOP | L_FARM_FIELD_APPLE | L_FARM_FIELD_DAIRY); + this->DamageLayer[_tile] = 0; + this->BuildingLayer[_tile] = 0; + if (DAT_BuildingsState::instance.buildings[buildingID].noRubble == 0) { + this->BuildingWasLayer[_tile] = '\0'; + } + this->ChangedLayer[_tile] = 2; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)( + (int)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile], _tile); + /* + process next tile + */ + _pTileRef = &_pTileRef->tileRefs[1]; + surfaceArea = surfaceArea + -1; + } while (surfaceArea != 0); + } + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeApplefarm.cpp b/src/OpenSHC/Map/TileMapState/placeApplefarm.cpp new file mode 100644 index 000000000..fefdae821 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeApplefarm.cpp @@ -0,0 +1,132 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00515740 + void TileMapState::placeApplefarm( + int playerID, uint x, uint y, BuildingType buildingType, undefined4 param_5, int param_6, int* param_7) + { + int _buildingID; + int iVar1; + int local_4; + int _buildingTileRef; + local_4 = 0; + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, x, y, (undefined4)((int)(param_7)), (int)(short)(undefined2)buildingType, 3, playerID, param_6); + this->placedBuildingID = _buildingID; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::markBuildingFootprintFlag, this)(x, (int)((int)(y)), 10); + _buildingTileRef = DAT_TerrainDefinedData::instance.AppleFarmOffsets[1].y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[0] + = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.AppleFarmOffsets[0].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[0].x + x; + iVar1 = DAT_TerrainDefinedData::instance.AppleFarmOffsets[2].y + y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[1] + = DAT_ViewportRenderState::instance.translationMatrix[_buildingTileRef + y].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[1].x + x; + _buildingTileRef = DAT_TerrainDefinedData::instance.AppleFarmOffsets[3].y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[2] + = DAT_ViewportRenderState::instance.translationMatrix[iVar1].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[2].x + x; + iVar1 = DAT_TerrainDefinedData::instance.AppleFarmOffsets[4].y + y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[3] + = DAT_ViewportRenderState::instance.translationMatrix[_buildingTileRef + y].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[3].x + x; + _buildingTileRef = DAT_TerrainDefinedData::instance.AppleFarmOffsets[5].y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[4] + = DAT_ViewportRenderState::instance.translationMatrix[iVar1].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[4].x + x; + iVar1 = DAT_TerrainDefinedData::instance.AppleFarmOffsets[6].y + y; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[5] + = DAT_ViewportRenderState::instance.translationMatrix[_buildingTileRef + y].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[5].x + x; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[6] + = DAT_ViewportRenderState::instance.translationMatrix[iVar1].addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[6].x + x; + DAT_BuildingsState::instance.buildings[_buildingID].tileRefs[7] + = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.AppleFarmOffsets[7].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.AppleFarmOffsets[7].x + x; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(local_4, 3); + param_6._0_2_ = (short)_buildingID; + _buildingTileRef = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + x + + this->buildingX; + this->HeightLayer[_buildingTileRef] = (byte)param_7; + this->LogicLayer[_buildingTileRef] = this->LogicLayer[_buildingTileRef] | 0x400; + this->BuildingLayer[_buildingTileRef] = (short)param_6; + this->BuildingWasLayer[_buildingTileRef] = (undefined1)buildingType; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)(playerID, _buildingTileRef, + this->buildingY + y, 2, OpenSHC::Map::LogicHelpers::L_NONE, OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB); + local_4 = local_4 + 1; + this->ChangedLayer[_buildingTileRef] = 2; + } while (local_4 < this->constructionTileCount); + /* + &tileRefs[0] of buildingID + */ + buildingType = _buildingID * 0x32c + OpenSHC::Map::Buildings::0xf986fc; + /* + apple tree relative coordinates + */ + param_7 = &DAT_TerrainDefinedData::instance.AppleFarmOffsets[0].x; + do { + _buildingTileRef = *(int*)buildingType; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(_buildingTileRef); + this->LogicLayer[_buildingTileRef] = this->LogicLayer[_buildingTileRef] | 0x4000000; + this->ChangedLayer[_buildingTileRef] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::placeAppleTree, DAT_LandscapeState::ptr)( + _buildingID, (undefined4)((int)(*param_7 + x)), (undefined4)((int)(param_7[1] + y))); + buildingType = buildingType + OpenSHC::Map::Buildings::BT_OXTETHER; + param_7 = param_7 + 2; + } while ((int)param_7 < 0xb49eb0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(_buildingID); + if (((playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingTypeBasedEmployeeCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || (DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)))) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)(1, 0x4d, 1, (TextMessageBLLookupStructUnion)0x0, 100, 6000); + } + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeBarracks.cpp b/src/OpenSHC/Map/TileMapState/placeBarracks.cpp new file mode 100644 index 000000000..8abc62855 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeBarracks.cpp @@ -0,0 +1,182 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005076A0 + void TileMapState::placeBarracks(int playerID, uint xPosition, int* yPosition_param, undefined4 buildingType, + uint buildingSize, int buildingOrientation, undefined4 param_7) + { + int* piVar1; + int _buildingID; + int iVar2; + int iVar3; + uint uVar4; + int iVar5; + uint uVar6; + int iVar7; + int local_c; + piVar1 = yPosition_param; + iVar7 = DAT_GameCore::instance.uniqueGameObjectTracker; + iVar5 = 0; + if (buildingOrientation == 0xf) { + local_c = 0; + } else { + local_c = buildingOrientation / 2; + } + _buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(playerID, xPosition, (uint)((int)(yPosition_param)), (undefined4)((int)(param_7)), + (BuildingType)((int)((int)(short)buildingType)), buildingSize, playerID, 0xf); + iVar2 = (int)(short)_buildingID; + this->placedBuildingID = iVar2; + DAT_BuildingsState::instance.buildings[iVar2].uidWhenPlaced = iVar7; + yPosition_param = &DAT_BuildingsState::instance.buildings[iVar2].tileRefs[0]; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar5, (int)((int)(buildingSize))); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + (int)piVar1].addXgetTile + + this->buildingX + xPosition; + *yPosition_param = iVar3; + this->HeightLayer[iVar3] = (byte)param_7; + this->LogicLayer[iVar3] = this->LogicLayer[iVar3] | 0x400; + this->BuildingLayer[iVar3] = (short)_buildingID; + iVar5 = iVar5 + 1; + yPosition_param = yPosition_param + 1; + this->BuildingWasLayer[iVar3] = (uchar)buildingType; + this->ChangedLayer[iVar3] = 2; + } while (iVar5 < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(iVar2); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(iVar2); + uVar6 = (int)piVar1 + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][0].y; + uVar4 = xPosition + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][0].x; + iVar5 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, uVar4, + uVar6, (undefined4)((int)(param_7)), OpenSHC::Map::Buildings::BT_PARADEGROUND3, 5, playerID, 0xf); + _buildingID = (int)(short)iVar5; + DAT_BuildingsState::instance.buildings[_buildingID].uidWhenPlaced = iVar7; + DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID = (undefined2)this->placedBuildingID; + buildingSize = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSize, (int)((int)(DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight))); + iVar2 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + uVar6].addXgetTile + + this->buildingX + uVar4; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar2); + this->HeightLayer[iVar2] = (byte)param_7; + if ((this->buildingX == 2) && (this->buildingY == 2)) { + this->LogicLayer[iVar2] = this->LogicLayer[iVar2] | 0x400; + } + this->BuildingLayer[iVar2] = (short)iVar5; + buildingSize = buildingSize + 1; + this->BuildingWasLayer[iVar2] = (uchar)buildingType; + this->ChangedLayer[iVar2] = 2; + } while ((int)buildingSize < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, uVar4, uVar6); + uVar6 = DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][1].y + (int)piVar1; + uVar4 = DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][1].x + xPosition; + iVar5 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, uVar4, + uVar6, (undefined4)((int)(param_7)), OpenSHC::Map::Buildings::BT_PARADEGROUND4, 5, playerID, 0xf); + _buildingID = (int)(short)iVar5; + DAT_BuildingsState::instance.buildings[_buildingID].uidWhenPlaced = iVar7; + DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID = (undefined2)this->placedBuildingID; + buildingSize = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSize, (int)((int)(DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight))); + iVar2 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + uVar6].addXgetTile + + this->buildingX + uVar4; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar2); + this->HeightLayer[iVar2] = (byte)param_7; + if ((this->buildingX == 2) && (this->buildingY == 2)) { + this->LogicLayer[iVar2] = this->LogicLayer[iVar2] | 0x400; + } + this->BuildingLayer[iVar2] = (short)iVar5; + buildingSize = buildingSize + 1; + this->BuildingWasLayer[iVar2] = (uchar)buildingType; + this->ChangedLayer[iVar2] = 2; + } while ((int)buildingSize < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, uVar4, uVar6); + uVar6 = DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][2].y + (int)piVar1; + uVar4 = DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_c][2].x + xPosition; + iVar5 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, uVar4, + uVar6, (undefined4)((int)(param_7)), OpenSHC::Map::Buildings::BT_PARADEGROUND2, 5, playerID, 0xf); + _buildingID = (int)(short)iVar5; + DAT_BuildingsState::instance.buildings[_buildingID].uidWhenPlaced = iVar7; + DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID = (undefined2)this->placedBuildingID; + buildingSize = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSize, (int)((int)(DAT_BuildingsState::instance.buildings[_buildingID].widthOrHeight))); + iVar7 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + uVar6].addXgetTile + + this->buildingX + uVar4; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar7); + this->HeightLayer[iVar7] = (byte)param_7; + if ((this->buildingX == 2) && (this->buildingY == 2)) { + this->LogicLayer[iVar7] = this->LogicLayer[iVar7] | 0x400; + } + this->BuildingLayer[iVar7] = (short)iVar5; + this->BuildingWasLayer[iVar7] = (uchar)buildingType; + buildingSize = buildingSize + 1; + this->ChangedLayer[iVar7] = 2; + } while ((int)buildingSize < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(_buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, uVar4, uVar6); + if ((short)buildingType == 8) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupMercenaryPostCampgroundPositions, + DAT_BuildingsState::ptr)(playerID); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBarracksCampgroundPositions, + DAT_BuildingsState::ptr)(playerID); + } + if (((playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingTypeBasedEmployeeCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || (DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)))) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)(1, 0x4d, 1, (TextMessageBLLookupStructUnion)0x0, 100, 6000); + } + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeDairyfarm.cpp b/src/OpenSHC/Map/TileMapState/placeDairyfarm.cpp new file mode 100644 index 000000000..4e4f3ee8a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeDairyfarm.cpp @@ -0,0 +1,126 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005154D0 + void TileMapState::placeDairyfarm(int param_1, uint param_2, uint param_3, undefined4 param_4, undefined4 param_5, + int* param_6, undefined4 param_7) + { + int iVar1; + uint uVar2; + int buildingID; + int iVar3; + int* piVar4; + int iVar5; + uVar2 = param_3; + iVar3 = 0; + buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(param_1, param_2, param_3, (undefined4)((int)(param_7)), + (BuildingType)((int)((int)(short)param_4)), 3, param_1, (int)((int)(param_6))); + this->placedBuildingID = buildingID; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::markBuildingFootprintFlag, this)( + param_2, (int)((int)(param_3)), 10); + iVar5 = 0; + param_6 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[0]; + do { + iVar1 = DAT_GameState::instance.playerDataArray[param_1].dairyFarmVariationMod4; + /* + 0 to 3*27 + 26 = 107 + */ + iVar1 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field1009_0xf5c[iVar1][iVar5].offset.y + + param_3] + .addXgetTile + + DAT_TerrainDefinedData::instance.field1009_0xf5c[iVar1][iVar5].offset.x + param_2; + *param_6 = iVar1; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar1); + if (3 < iVar5) { + this->DamageLayer[*param_6] + = (byte)DAT_TerrainDefinedData::instance + .field1009_0xf5c[DAT_GameState::instance.playerDataArray[param_1].dairyFarmVariationMod4] + [iVar5] + .property; + } + param_6 = param_6 + 1; + iVar5 = iVar5 + 1; + } while (iVar5 < 27); + piVar4 = &DAT_GameState::instance.playerDataArray[param_1].dairyFarmVariationMod4; + *piVar4 = *piVar4 + 1; + if (3 < DAT_GameState::instance.playerDataArray[param_1].dairyFarmVariationMod4) { + DAT_GameState::instance.playerDataArray[param_1].dairyFarmVariationMod4 = 0; + } + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(iVar3, 3); + param_3._0_2_ = (short)buildingID; + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + uVar2].addXgetTile + + this->buildingX + param_2; + this->HeightLayer[iVar5] = (byte)param_7; + this->LogicLayer[iVar5] = this->LogicLayer[iVar5] | 0x400; + this->BuildingLayer[iVar5] = (short)param_3; + this->BuildingWasLayer[iVar5] = (uchar)param_4; + this->ChangedLayer[iVar5] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)(param_1, iVar5, + this->buildingY + uVar2, 2, OpenSHC::Map::LogicHelpers::L_NONE, + OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB); + iVar3 = iVar3 + 1; + } while (iVar3 < this->constructionTileCount); + piVar4 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[4]; + iVar3 = 23; + do { + iVar5 = *piVar4; + this->LogicLayer[iVar5] = this->LogicLayer[iVar5] | 0x8000000; + this->BuildingLayer[iVar5] = (short)param_3; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)( + (int)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[iVar5], iVar5); + piVar4 = piVar4 + 1; + iVar3 = iVar3 + -1; + this->BuildingWasLayer[iVar5] = (uchar)param_4; + this->ChangedLayer[iVar5] = 2; + } while (iVar3 != 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + if (((param_1 == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[param_1].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount)) + && ((DAT_GameState::instance.playerDataArray[param_1].populationCap + <= DAT_GameState::instance.playerDataArray[param_1].currentPopulation + || (DAT_GameState::instance.playerDataArray[param_1].popularity < 5000)))) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)(1, 0x4d, 1, (TextMessageBLLookupStructUnion)0x0, 100, 6000); + } + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeDrawbridge.cpp b/src/OpenSHC/Map/TileMapState/placeDrawbridge.cpp new file mode 100644 index 000000000..b123fac22 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeDrawbridge.cpp @@ -0,0 +1,68 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00514DE0 + void TileMapState::placeDrawbridge( + int playerID, uint x, uint y, undefined4 buildingType, uint width, int* orientation, undefined4 averageHeight) + { + int buildingID; + int _tileIndex; + Building* _pTileRef; + int tile; + _tileIndex = 0; + buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(playerID, x, y, (undefined4)((int)(averageHeight)), + (BuildingType)((int)((int)(short)buildingType)), width, playerID, (int)((int)(orientation))); + orientation = DAT_TerrainDefinedData::instance.DrawbridgeOrientationMapping[(int)orientation / 2]; + _pTileRef = &DAT_BuildingsState::instance.buildings[buildingID]; + this->placedBuildingID = buildingID; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + _tileIndex, (int)((int)(width))); + /* + fixme: repurposed parameter + */ + averageHeight._0_2_ = (short)buildingID; + tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + _pTileRef->tileRefs[0] = tile; + this->BuildingLayer[tile] = (short)averageHeight; + this->BuildingWasLayer[tile] = (uchar)buildingType; + this->ChangedLayer[tile] = 2; + if (DAT_TerrainDefinedData::instance.DrawbridgeTileMoatProperty[_tileIndex] != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | 1024; + } + if (*orientation == 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_MOAT); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::createMoatData, this)( + playerID, this->buildingX + x, this->buildingY + y, 1); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_MOAT); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMoatVisualStateAtTile, this)(tile, 0); + this->HeightLayer[tile] = 0; + } + orientation = orientation + 1; + _tileIndex = _tileIndex + 1; + _pTileRef = &_pTileRef->tileRefs[1]; + } while (_tileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeEngineersguild.cpp b/src/OpenSHC/Map/TileMapState/placeEngineersguild.cpp new file mode 100644 index 000000000..eba40b8f6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeEngineersguild.cpp @@ -0,0 +1,99 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507BD0 + void TileMapState::placeEngineersguild( + int param_1, int* param_2, uint param_3, undefined4 param_4, uint param_5, int param_6, undefined4 param_7) + { + int* piVar1; + int iVar2; + int buildingID; + int iVar3; + uint y; + uint x; + int iVar4; + int iVar5; + int local_8; + piVar1 = param_2; + iVar5 = DAT_GameCore::instance.uniqueGameObjectTracker; + iVar4 = 0; + if (param_6 == 0xf) { + local_8 = 0; + } else { + local_8 = param_6 / 2; + } + iVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(param_1, (uint)((int)(param_2)), param_3, (undefined4)((int)(param_7)), + (BuildingType)((int)((int)(short)param_4)), param_5, param_1, 0xf); + buildingID = (int)(short)iVar2; + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = iVar5; + param_2 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[0]; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar4, (int)((int)(param_5))); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + this->buildingX + (int)piVar1; + *param_2 = iVar3; + this->HeightLayer[iVar3] = (byte)param_7; + this->LogicLayer[iVar3] = this->LogicLayer[iVar3] | 1024; + this->BuildingLayer[iVar3] = (short)iVar2; + iVar4 = iVar4 + 1; + param_2 = param_2 + 1; + this->BuildingWasLayer[iVar3] = (uchar)param_4; + this->ChangedLayer[iVar3] = 2; + } while (iVar4 < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + x = (int)piVar1 + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_8][1].x; + y = param_3 + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_8][1].y; + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, x, y, (undefined4)((int)(param_7)), OpenSHC::Map::Buildings::BT_PARADEGROUND, 5, param_1, 0xf); + iVar2 = (int)(short)iVar4; + DAT_BuildingsState::instance.buildings[iVar2].uidWhenPlaced = iVar5; + DAT_BuildingsState::instance.buildings[iVar2].quarryStockpileID = (undefined2)this->placedBuildingID; + param_5 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + param_5, (int)((int)(DAT_BuildingsState::instance.buildings[iVar2].widthOrHeight))); + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar5); + this->HeightLayer[iVar5] = (byte)param_7; + this->BuildingLayer[iVar5] = (short)iVar4; + param_5 = param_5 + 1; + this->BuildingWasLayer[iVar5] = (uchar)param_4; + this->ChangedLayer[iVar5] = 2; + } while ((int)param_5 < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(iVar2); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(iVar2); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, x, y); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupEngineersGuildParagroundPositions, + DAT_BuildingsState::ptr)(param_1); + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeHopfarm.cpp b/src/OpenSHC/Map/TileMapState/placeHopfarm.cpp new file mode 100644 index 000000000..1a90b369f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeHopfarm.cpp @@ -0,0 +1,136 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005151C0 + void TileMapState::placeHopfarm( + int param_1, uint param_2, uint param_3, undefined4 param_4, undefined4 param_5, int param_6, int param_7) + { + undefined1* puVar1; + uint uVar2; + int buildingID; + XYPair* pXVar3; + int iVar4; + int* piVar5; + int buildingSizeTileIndex; + uVar2 = param_2; + buildingSizeTileIndex = 0; + buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(param_1, param_2, + param_3, (undefined4)((int)(param_7)), (BuildingType)((int)((int)(short)param_4)), 3, param_1, param_6); + this->placedBuildingID = buildingID; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::markBuildingFootprintFlag, this)( + param_2, (int)((int)(param_3)), 9); + iVar4 = *(int*)&DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation; + param_2 = 4; + pXVar3 = DAT_TerrainDefinedData::instance.HopFarmProperty1[iVar4]; + piVar5 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[1]; + do { + piVar5[-1] = DAT_ViewportRenderState::instance.translationMatrix[pXVar3->y + param_3].addXgetTile + + ((XYPair*)&pXVar3->x)->x + uVar2; + *piVar5 = DAT_ViewportRenderState::instance.translationMatrix[pXVar3[1].y + param_3].addXgetTile + + pXVar3[1].x + uVar2; + piVar5[1] = DAT_ViewportRenderState::instance.translationMatrix[pXVar3[2].y + param_3].addXgetTile + + pXVar3[2].x + uVar2; + piVar5[2] = DAT_ViewportRenderState::instance.translationMatrix[pXVar3[3].y + param_3].addXgetTile + + pXVar3[3].x + uVar2; + piVar5[3] = DAT_ViewportRenderState::instance.translationMatrix[pXVar3[4].y + param_3].addXgetTile + + pXVar3[4].x + uVar2; + param_2 = param_2 - 1; + piVar5[4] = DAT_ViewportRenderState::instance.translationMatrix[pXVar3[5].y + param_3].addXgetTile + + pXVar3[5].x + uVar2; + pXVar3 = pXVar3 + 6; + piVar5 = piVar5 + 6; + } while (param_2 != 0); + *(ushort*)&DAT_BuildingsState::instance.buildings[buildingID].field_0x26e + = (-(ushort)(iVar4 != 0) & 0xffb6) + 0x51; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 3); + param_6._0_2_ = (short)buildingID; + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + this->buildingX + uVar2; + this->HeightLayer[iVar4] = (byte)param_7; + this->LogicLayer[iVar4] = this->LogicLayer[iVar4] | 1024; + this->BuildingLayer[iVar4] = (short)param_6; + this->BuildingWasLayer[iVar4] = (uchar)param_4; + this->ChangedLayer[iVar4] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)(param_1, iVar4, + this->buildingY + param_3, 2, OpenSHC::Map::LogicHelpers::L_NONE, + OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB); + buildingSizeTileIndex = buildingSizeTileIndex + 1; + } while (buildingSizeTileIndex < this->constructionTileCount); + param_7 = 0; + do { + iVar4 = *(int*)&DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation; + iVar4 + = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.HopFarmProperty1[iVar4][param_7].y + param_3] + .addXgetTile + + DAT_TerrainDefinedData::instance.HopFarmProperty1[iVar4][param_7].x + uVar2; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar4); + this->LogicLayer[iVar4] = this->LogicLayer[iVar4] | 33554432; + this->BuildingLayer[iVar4] = (short)param_6; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)( + DAT_TerrainDefinedData::instance + .HopFarmProperty1[*(int*)&DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation] + [param_7] + .y + + param_3, + iVar4); + param_7 = param_7 + 1; + this->BuildingWasLayer[iVar4] = (uchar)param_4; + this->ChangedLayer[iVar4] = 2; + } while (param_7 < 0x18); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + puVar1 = &DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation; + *(int*)puVar1 = *(int*)puVar1 + 1; + if (1 < *(int*)&DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation) { + *(undefined4*)&DAT_GameState::instance.playerDataArray[param_1].unkHopFarmVariation = 0; + } + if (((param_1 == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[param_1].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount)) + && ((DAT_GameState::instance.playerDataArray[param_1].populationCap + <= DAT_GameState::instance.playerDataArray[param_1].currentPopulation + || (DAT_GameState::instance.playerDataArray[param_1].popularity < 5000)))) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)(1, 0x4d, 1, (TextMessageBLLookupStructUnion)0x0, 100, 6000); + } + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeTunnelersguild.cpp b/src/OpenSHC/Map/TileMapState/placeTunnelersguild.cpp new file mode 100644 index 000000000..322e0500a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeTunnelersguild.cpp @@ -0,0 +1,99 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507E00 + void TileMapState::placeTunnelersguild( + int param_1, int* param_2, uint param_3, undefined4 param_4, uint param_5, int param_6, undefined4 param_7) + { + int* piVar1; + int iVar2; + int buildingID; + int iVar3; + uint y; + uint x; + int iVar4; + int iVar5; + int local_8; + piVar1 = param_2; + iVar5 = DAT_GameCore::instance.uniqueGameObjectTracker; + iVar4 = 0; + if (param_6 == 0xf) { + local_8 = 0; + } else { + local_8 = param_6 / 2; + } + iVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(param_1, (uint)((int)(param_2)), param_3, (undefined4)((int)(param_7)), + (BuildingType)((int)((int)(short)param_4)), param_5, param_1, 0xf); + buildingID = (int)(short)iVar2; + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = iVar5; + param_2 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[0]; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar4, (int)((int)(param_5))); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + this->buildingX + (int)piVar1; + *param_2 = iVar3; + this->HeightLayer[iVar3] = (byte)param_7; + this->LogicLayer[iVar3] = this->LogicLayer[iVar3] | 1024; + this->BuildingLayer[iVar3] = (short)iVar2; + iVar4 = iVar4 + 1; + param_2 = param_2 + 1; + this->BuildingWasLayer[iVar3] = (uchar)param_4; + this->ChangedLayer[iVar3] = 2; + } while (iVar4 < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + x = (int)piVar1 + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_8][1].x; + y = param_3 + DAT_TerrainDefinedData::instance.BuildingPartsOffsets[local_8][1].y; + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, x, y, (undefined4)((int)(param_7)), OpenSHC::Map::Buildings::BT_PARADEGROUND5, 5, param_1, 0xf); + iVar2 = (int)(short)iVar4; + DAT_BuildingsState::instance.buildings[iVar2].uidWhenPlaced = iVar5; + DAT_BuildingsState::instance.buildings[iVar2].quarryStockpileID = (undefined2)this->placedBuildingID; + param_5 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + param_5, (int)((int)(DAT_BuildingsState::instance.buildings[iVar2].widthOrHeight))); + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar5); + this->HeightLayer[iVar5] = (byte)param_7; + this->BuildingLayer[iVar5] = (short)iVar4; + param_5 = param_5 + 1; + this->BuildingWasLayer[iVar5] = (uchar)param_4; + this->ChangedLayer[iVar5] = 2; + } while ((int)param_5 < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(iVar2); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(iVar2); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, x, y); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupTunnelersGuildCampgroundPositions, + DAT_BuildingsState::ptr)(param_1); + return; + } + +} +} diff --git a/src/OpenSHC/Map/TileMapState/placeWheatfarm.cpp b/src/OpenSHC/Map/TileMapState/placeWheatfarm.cpp new file mode 100644 index 000000000..8f385cf9a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeWheatfarm.cpp @@ -0,0 +1,120 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00514F30 + void TileMapState::placeWheatfarm(int playerID, uint x, uint y, undefined4 buildingType, undefined4 param_5, + int variation, undefined4 averageHeight) + { + uint uVar1; + int buildingID; + XYPair* pXVar2; + int iVar3; + int* piVar4; + int iVar5; + uVar1 = x; + iVar5 = 0; + buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, + DAT_BuildingsState::ptr)(playerID, x, y, (undefined4)((int)(averageHeight)), + (BuildingType)((int)((int)(short)buildingType)), 3, playerID, variation); + this->placedBuildingID = buildingID; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::markBuildingFootprintFlag, this)(x, (int)((int)(y)), 9); + x = 6; + pXVar2 = DAT_TerrainDefinedData::instance + .WheatFarmTiles[DAT_GameState::instance.playerDataArray[playerID].unkWheatFarmOrientation]; + piVar4 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[1]; + do { + piVar4[-1] = DAT_ViewportRenderState::instance.translationMatrix[pXVar2->y + y].addXgetTile + uVar1 + + ((XYPair*)&pXVar2->x)->x; + *piVar4 = DAT_ViewportRenderState::instance.translationMatrix[pXVar2[1].y + y].addXgetTile + pXVar2[1].x + + uVar1; + piVar4[1] = DAT_ViewportRenderState::instance.translationMatrix[pXVar2[2].y + y].addXgetTile + pXVar2[2].x + + uVar1; + piVar4[2] = DAT_ViewportRenderState::instance.translationMatrix[pXVar2[3].y + y].addXgetTile + pXVar2[3].x + + uVar1; + piVar4[3] = DAT_ViewportRenderState::instance.translationMatrix[pXVar2[4].y + y].addXgetTile + pXVar2[4].x + + uVar1; + x = x - 1; + piVar4[4] = DAT_ViewportRenderState::instance.translationMatrix[pXVar2[5].y + y].addXgetTile + pXVar2[5].x + + uVar1; + pXVar2 = pXVar2 + 6; + piVar4 = piVar4 + 6; + } while (x != 0); + iVar3 = DAT_GameState::instance.playerDataArray[playerID].unkWheatFarmOrientation + 1; + DAT_GameState::instance.playerDataArray[playerID].unkWheatFarmOrientation = iVar3; + if (1 < iVar3) { + DAT_GameState::instance.playerDataArray[playerID].unkWheatFarmOrientation = 0; + } + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(iVar5, 3); + /* + fixme: repurposed + */ + variation._0_2_ = (short)buildingID; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + uVar1 + + this->buildingX; + this->HeightLayer[iVar3] = (byte)averageHeight; + this->LogicLayer[iVar3] = this->LogicLayer[iVar3] | 1024; + this->BuildingLayer[iVar3] = (short)variation; + this->BuildingWasLayer[iVar3] = (uchar)buildingType; + this->ChangedLayer[iVar3] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)(playerID, iVar3, this->buildingY + y, + 2, OpenSHC::Map::LogicHelpers::L_NONE, OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB); + iVar5 = iVar5 + 1; + } while (iVar5 < this->constructionTileCount); + piVar4 = &DAT_BuildingsState::instance.buildings[buildingID].tileRefs[0]; + iVar5 = 0x24; + do { + iVar3 = *piVar4; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(iVar3); + this->LogicLayer[iVar3] = this->LogicLayer[iVar3] | 16777216; + this->BuildingLayer[iVar3] = (short)variation; + piVar4 = piVar4 + 1; + iVar5 = iVar5 + -1; + this->BuildingWasLayer[iVar3] = (uchar)buildingType; + this->ChangedLayer[iVar3] = 2; + } while (iVar5 != 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + if (((playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || (DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)))) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)(1, 0x4d, 1, (TextMessageBLLookupStructUnion)0x0, 100, 6000); + } + return; + } + +} +} From 7f521bf9cb6a26948c043672327a4a1463b09576 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:20:00 +0200 Subject: [PATCH 064/252] build: give each worktree its own mspdbsrv endpoint mspdbsrv.exe is a per-user singleton keyed on _MSPDBSRV_ENDPOINT_, and every worktree carries its own copy of MSVC1400-SP1. Two worktrees building at the same time shared one server and one image name, so: - cl.exe could end up talking to another worktree's copy of mspdbsrv, and - the unconditional "taskkill /f /im mspdbsrv.exe" at the start of a build took down the PDB server of any other worktree mid-compile. Either way the other build dies with "fatal error C1090: PDB API call failed, error code '23'", usually while expanding a precompiled header, so the error points at xstring or FunctionResolver.h rather than at anything the author changed. Derive the endpoint from the worktree directory name and kill only the mspdbsrv running out of this worktree. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A4PvfebpUzaMXy93EutBjJ --- build.bat | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/build.bat b/build.bat index 40f1f3b08..028dee29a 100644 --- a/build.bat +++ b/build.bat @@ -23,16 +23,21 @@ if "%~1"=="" ( set "PRESET=%~1" set "TARGET=%~2" -:: --- Kill mspdbsrv.exe if it's running --- -tasklist | find /I "mspdbsrv.exe" >nul -if not errorlevel 1 ( - if not defined WRAP_QUIET echo Stopping mspdbsrv.exe... - taskkill /f /t /im mspdbsrv.exe >nul - if errorlevel 1 ( - if not defined WRAP_QUIET echo [WARNING] Failed to stop mspdbsrv.exe, continuing... - ) +:: --- Give this worktree its own PDB server --- +:: mspdbsrv.exe is a per-user singleton keyed on _MSPDBSRV_ENDPOINT_, and every worktree +:: carries its own copy of the toolchain. Sharing one endpoint across worktrees makes +:: cl.exe talk to whichever copy started first and fail with +:: fatal error C1090: PDB API call failed, error code '23' +if not defined _MSPDBSRV_ENDPOINT_ ( + for %%I in ("%~dp0.") do set "_MSPDBSRV_ENDPOINT_=openshc_%%~nxI" ) +:: --- Kill this worktree's mspdbsrv.exe if it's running --- +:: Only ours: killing every instance by image name takes down the PDB server of any other +:: worktree that is building at the same time, which fails their build with C1090. +powershell -NoProfile -Command ^ + "Get-Process mspdbsrv -ErrorAction SilentlyContinue | Where-Object { $_.Path -like '%~dp0*' } | Stop-Process -Force -ErrorAction SilentlyContinue" >nul 2>&1 + :: --- Run cmake configure using preset --- if not defined WRAP_QUIET echo [INFO] Configuring with preset "%PRESET%"... call .\cmakew --preset "%PRESET%" From 8019d9d657acab7ddbc6da33c232963b96c17b7b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:02 +0200 Subject: [PATCH 065/252] reimplement: SHC_3BB0A8C1_0x004FFB10 100.00% Reimplemented --- .../Map/TileMapState/getTotalHeightAtTile.cpp | 43 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getTotalHeightAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/getTotalHeightAtTile.cpp b/src/OpenSHC/Map/TileMapState/getTotalHeightAtTile.cpp new file mode 100644 index 000000000..cb093d406 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getTotalHeightAtTile.cpp @@ -0,0 +1,43 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FFB10 + uint TileMapState::getTotalHeightAtTile(int tile) + { + int buildingID = this->BuildingLayer[tile]; + if (buildingID != 0) { + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE) { + return MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(buildingID) + + this->DefaultHeightLayer[tile]; + } + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL) { + return MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(buildingID) + + this->DefaultHeightLayer[tile]; + } + return MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(buildingID) + + this->HeightLayer[tile]; + } + return this->HeightLayer[tile]; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 847a0f686..b62db8491 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41259,7 +41259,7 @@ SHC_3BB0A8C1_0x004FFB02 | 0.0% | Pending SHC_3BB0A8C1_0x004FFB03 | 0.0% | Pending -SHC_3BB0A8C1_0x004FFB10 | 0.0% | Pending +SHC_3BB0A8C1_0x004FFB10 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004FFBA0 | 0.0% | Pending From 3072d9d6ad146c5add549234b23a12c4c2118234 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:02 +0200 Subject: [PATCH 066/252] reimplement: SHC_3BB0A8C1_0x004FB360 78.95% ecx not kept across callee --- .../clearBuildingDisplayFlagsAndEntities.cpp | 40 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingDisplayFlagsAndEntities.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingDisplayFlagsAndEntities.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingDisplayFlagsAndEntities.cpp new file mode 100644 index 000000000..9b01d6b50 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingDisplayFlagsAndEntities.cpp @@ -0,0 +1,40 @@ + +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB360 + void TileMapState::clearBuildingDisplayFlagsAndEntities(int buildingID, int param_2) + { + int buildingX = DAT_BuildingsState::instance.buildings[buildingID].x; + int buildingY = DAT_BuildingsState::instance.buildings[buildingID].y; + uint widthOrHeight = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, widthOrHeight); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + buildingY].addXgetTile + + this->buildingX + buildingX; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfff3; + if (param_2 == 1) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, DAT_EntityState::ptr)(tile); + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b62db8491..407c50a30 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40565,7 +40565,7 @@ SHC_3BB0A8C1_0x004FB354 | 0.0% | Pending SHC_3BB0A8C1_0x004FB358 | 0.0% | Pending -SHC_3BB0A8C1_0x004FB360 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB360 | 79.0% | ecx not kept across callee SHC_3BB0A8C1_0x004FB3F0 | 0.0% | Pending From c99190f8447a06f0aa2227d51ed3bcb1b8eba0a6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:03 +0200 Subject: [PATCH 067/252] reimplement: SHC_3BB0A8C1_0x00500BB0 100.00% Reimplemented --- .../setSignpostDistanceForCampaignMission.cpp | 46 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setSignpostDistanceForCampaignMission.cpp diff --git a/src/OpenSHC/Map/TileMapState/setSignpostDistanceForCampaignMission.cpp b/src/OpenSHC/Map/TileMapState/setSignpostDistanceForCampaignMission.cpp new file mode 100644 index 000000000..4a239a3a7 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setSignpostDistanceForCampaignMission.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_MapPropertiesState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Game::GameMode2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500BB0 + void TileMapState::setSignpostDistanceForCampaignMission() + { + DAT_GameState::instance.mapAndTime.unk_signpostDistance = 30; + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION) { + if (DAT_GameCore::instance.missionNumber1to20 <= 2) { + DAT_GameState::instance.mapAndTime.unk_signpostDistance = 0; + return; + } + if (DAT_GameCore::instance.missionNumber1to20 <= 4) { + DAT_GameState::instance.mapAndTime.unk_signpostDistance = 15; + return; + } + if (DAT_GameCore::instance.missionNumber1to20 == 6) { + DAT_GameState::instance.mapAndTime.unk_signpostDistance = 37; + } + return; + } + + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_ECONOMIC_CAMPAIGN_SH1 + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_BUILDERUnk + && (int)DAT_MapPropertiesState::instance.SEC_U3_MapType2_1 >= 2)) { + DAT_GameState::instance.mapAndTime.unk_signpostDistance = 7; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 407c50a30..3f5fd1f09 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41469,7 +41469,7 @@ SHC_3BB0A8C1_0x00500980 | 0.0% | Pending SHC_3BB0A8C1_0x00500B50 | 68.3% | loop guard/regalloc differs -SHC_3BB0A8C1_0x00500BB0 | 0.0% | Pending +SHC_3BB0A8C1_0x00500BB0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500C20 | 0.0% | Pending From 6d8c8ec95852822c70ff36e104fdeaa6d957e766 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:03 +0200 Subject: [PATCH 068/252] reimplement: SHC_3BB0A8C1_0x004F8160 100.00% Reimplemented --- ...NonFarmFieldBuildingHealthAtTileOr1000.cpp | 53 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getNonFarmFieldBuildingHealthAtTileOr1000.cpp diff --git a/src/OpenSHC/Map/TileMapState/getNonFarmFieldBuildingHealthAtTileOr1000.cpp b/src/OpenSHC/Map/TileMapState/getNonFarmFieldBuildingHealthAtTileOr1000.cpp new file mode 100644 index 000000000..9dbee901f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getNonFarmFieldBuildingHealthAtTileOr1000.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_DAIRY; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_HOP; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_WHEAT; + + using OpenSHC::Map::Buildings::BuildingLogicalState; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8160 + int TileMapState::getNonFarmFieldBuildingHealthAtTileOr1000(int tile) + { + short buildingID = this->BuildingLayer[tile]; + if (buildingID <= 0) { + return 1000; + } + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == 0) { + return 1000; + } + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == OpenSHC::Map::Buildings::BLS_REMOVE) { + return 1000; + } + if (DAT_BuildingsState::instance.buildings[buildingID].currentHealth == 0) { + return 1000; + } + if (DAT_BuildingDefinedData::instance + .BuildingTypeHasHealth[DAT_BuildingsState::instance.buildings[buildingID].buildingType] + == 0) { + return 1000; + } + + if ((this->LogicLayer[tile] & (L_FARM_FIELD_WHEAT | L_FARM_FIELD_HOP | L_FARM_FIELD_APPLE | L_FARM_FIELD_DAIRY)) + != 0) { + return 1000; + } + return DAT_BuildingsState::instance.buildings[buildingID].currentHealth; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3f5fd1f09..39805193a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38789,7 +38789,7 @@ SHC_3BB0A8C1_0x004F80D8 | 0.0% | Pending SHC_3BB0A8C1_0x004F80E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F8160 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8160 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F81D0 | 100.0% | Reimplemented From 52d5a74da8558a215b40661afd6401503c04f830 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:03 +0200 Subject: [PATCH 069/252] reimplement: SHC_3BB0A8C1_0x00511D70 100.00% Reimplemented --- .../upgradeMapFormatLogicLayer.cpp | 48 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/upgradeMapFormatLogicLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/upgradeMapFormatLogicLayer.cpp b/src/OpenSHC/Map/TileMapState/upgradeMapFormatLogicLayer.cpp new file mode 100644 index 000000000..1d5414792 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/upgradeMapFormatLogicLayer.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Version.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00511D70 + void TileMapState::upgradeMapFormatLogicLayer( + PackagedFileMagicNum receivedMapVersion, PackagedFileMagicNum packagerMapVersion) + { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_Unknown1)(); + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_Unknown2)(); + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_Unknown3)(); + if (this->mapSize == 0) { + this->mapSize = 400; + } + if (receivedMapVersion == packagerMapVersion) { + return; + } + + if ((int)receivedMapVersion < 0x66) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_102)(); + } + if ((int)receivedMapVersion < 0x78) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_120)(); + } + if ((int)receivedMapVersion < 0x7d) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_125)(); + } + if ((int)receivedMapVersion < 0x80) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_128)(); + } + if ((int)receivedMapVersion < 0x91) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_145)(); + } + if ((int)receivedMapVersion < 0x93) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpgradeMapLogicToVersion_147)(); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 39805193a..9c373e302 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44723,7 +44723,7 @@ SHC_3BB0A8C1_0x00511D60 | 0.0% | Pending SHC_3BB0A8C1_0x00511D64 | 0.0% | Pending -SHC_3BB0A8C1_0x00511D70 | 0.0% | Pending +SHC_3BB0A8C1_0x00511D70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00511DF0 | 0.0% | Pending From 1d040e106eea6019411de0d2c6e2099a24d21fb1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:04 +0200 Subject: [PATCH 070/252] reimplement: SHC_3BB0A8C1_0x004F8A40 87.18% shr vs sar on logic bit --- .../hasHigherNeighborWithStairs.cpp | 40 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/hasHigherNeighborWithStairs.cpp diff --git a/src/OpenSHC/Map/TileMapState/hasHigherNeighborWithStairs.cpp b/src/OpenSHC/Map/TileMapState/hasHigherNeighborWithStairs.cpp new file mode 100644 index 000000000..3a52d360f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/hasHigherNeighborWithStairs.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8A40 + BOOLEnum TileMapState::hasHigherNeighborWithStairs(int tile, int y, int direction) + { + int rotatedDirection = 0; + if (this->mapOrientation == 0) { + rotatedDirection = direction; + } else if (this->mapOrientation == 4) { + rotatedDirection = direction + 4; + } else if (this->mapOrientation == 2) { + rotatedDirection = direction + 2; + } else if (this->mapOrientation == 6) { + rotatedDirection = direction + 6; + } + if (rotatedDirection >= 8) { + rotatedDirection = rotatedDirection - 8; + } + + int neighbour = this->directionTranslationMatrix[y][rotatedDirection] + tile; + if (this->HeightLayer[neighbour] > this->HeightLayer[tile]) { + return this->LogicLayer[neighbour] >> 0xb & TRUE; + } + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9c373e302..dd28c590c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39371,7 +39371,7 @@ SHC_3BB0A8C1_0x004F8900 | 0.0% | Pending SHC_3BB0A8C1_0x004F89C0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8A40 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8A40 | 87.2% | shr vs sar on logic bit SHC_3BB0A8C1_0x004F8AC0 | 0.0% | Pending From 008e19f258ad3200f77e2e6da7c0ea35804e5b07 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:04 +0200 Subject: [PATCH 071/252] reimplement: SHC_3BB0A8C1_0x005000E0 48.72% owner reload per unrolled step --- .../countMoatsOwnedByEachPlayer.cpp | 35 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/countMoatsOwnedByEachPlayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/countMoatsOwnedByEachPlayer.cpp b/src/OpenSHC/Map/TileMapState/countMoatsOwnedByEachPlayer.cpp new file mode 100644 index 000000000..f6e120b27 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/countMoatsOwnedByEachPlayer.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005000E0 + void TileMapState::countMoatsOwnedByEachPlayer() + { + DAT_GameState::instance.playerDataArray[1].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[2].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[3].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[4].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[5].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[6].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[7].moatsOwned = 0; + DAT_GameState::instance.playerDataArray[8].moatsOwned = 0; + for (int moatID = 1; moatID < 16000; moatID++) { + char owner = this->moats[moatID].owner; + if (owner != 0) { + DAT_GameState::instance.playerDataArray[owner].moatsOwned + = DAT_GameState::instance.playerDataArray[owner].moatsOwned + 1; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index dd28c590c..4512f3d78 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41421,7 +41421,7 @@ SHC_3BB0A8C1_0x00500091 | 0.0% | Pending SHC_3BB0A8C1_0x005000A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005000E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005000E0 | 48.7% | owner reload per unrolled step SHC_3BB0A8C1_0x00500180 | 100.0% | Reimplemented From 30a74c0a6475c2d18782ed2a637673cb668f53f3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:04 +0200 Subject: [PATCH 072/252] reimplement: SHC_3BB0A8C1_0x00500800 100.00% Reimplemented --- .../TileMapState/countUnownedPitchDitches.cpp | 25 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/countUnownedPitchDitches.cpp diff --git a/src/OpenSHC/Map/TileMapState/countUnownedPitchDitches.cpp b/src/OpenSHC/Map/TileMapState/countUnownedPitchDitches.cpp new file mode 100644 index 000000000..2c34cd403 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/countUnownedPitchDitches.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500800 + int TileMapState::countUnownedPitchDitches() + { + int unownedPitchDitches = 0; + for (int pitchDitchID = 0; pitchDitchID < 4000; pitchDitchID++) { + if (this->pitchDitches[pitchDitchID].owner == 0) { + unownedPitchDitches++; + } + } + return unownedPitchDitches; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4512f3d78..9fbd69194 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41457,7 +41457,7 @@ SHC_3BB0A8C1_0x00500790 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005007D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500800 | 0.0% | Pending +SHC_3BB0A8C1_0x00500800 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500850 | 100.0% | Reimplemented From 6af3a584d660243848316a32f9f086e9e5c4c9ed Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:05 +0200 Subject: [PATCH 073/252] reimplement: SHC_3BB0A8C1_0x00501CD0 82.05% brush loop regalloc --- .../increaseHeightForTunnelWithBrush.cpp | 61 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/increaseHeightForTunnelWithBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelWithBrush.cpp b/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelWithBrush.cpp new file mode 100644 index 000000000..3b83fca06 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/increaseHeightForTunnelWithBrush.cpp @@ -0,0 +1,61 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501CD0 + void TileMapState::increaseHeightForTunnelWithBrush(int tile, uint x, uint y, int increment) + { + int baseTile = tile; + uint baseY = y; + for (int index = 0; index < 9; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 0, index, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0) { + continue; + } + if (this->BuildingLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & (L_SEA | L_BORDER | L_BORDER_EDGE | L_ROCKY)) != 0) { + continue; + } + if ((this->LogicLayer[tile] & (L_RIVER | L_FORD | L_MARSH | L_MOAT)) != 0) { + continue; + } + + if ((this->HeightLayer[tile] < 0x10 || this->DefaultHeightLayer[tile] < 0x10) + && (int)((uint)this->HeightLayer[tile] + increment) >= 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] + (char)increment; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(5, x, y); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9fbd69194..356fbf96c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41561,7 +41561,7 @@ SHC_3BB0A8C1_0x00501CC4 | 0.0% | Pending SHC_3BB0A8C1_0x00501CC8 | 0.0% | Pending -SHC_3BB0A8C1_0x00501CD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00501CD0 | 82.0% | brush loop regalloc SHC_3BB0A8C1_0x00501D90 | 0.0% | Pending From 0bd981b935b677eaf743230f0784d3d67ce97131 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:05 +0200 Subject: [PATCH 074/252] reimplement: SHC_3BB0A8C1_0x004FAEE0 55.32% ecx not kept across callee --- .../isUnitBlockingSizeFiveFootprint.cpp | 43 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isUnitBlockingSizeFiveFootprint.cpp diff --git a/src/OpenSHC/Map/TileMapState/isUnitBlockingSizeFiveFootprint.cpp b/src/OpenSHC/Map/TileMapState/isUnitBlockingSizeFiveFootprint.cpp new file mode 100644 index 000000000..fac316068 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isUnitBlockingSizeFiveFootprint.cpp @@ -0,0 +1,43 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAEE0 + BOOLEnum TileMapState::isUnitBlockingSizeFiveFootprint(int buildingID) + { + int buildingX = DAT_BuildingsState::instance.buildings[buildingID].x; + int buildingY = DAT_BuildingsState::instance.buildings[buildingID].y; + int variation = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation / 2; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 5); + if (DAT_TerrainDefinedData::instance.field2469_0x21ec[variation][buildingSizeTileIndex] == 0 + && this->UnitLayer[DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + buildingY] + .addXgetTile + + this->buildingX + buildingX] + != 0) { + return TRUE; + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 356fbf96c..3759cabd0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40365,7 +40365,7 @@ SHC_3BB0A8C1_0x004FAD70 | 0.0% | Pending SHC_3BB0A8C1_0x004FAE50 | 35.1% | ecx not kept across callee -SHC_3BB0A8C1_0x004FAEE0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAEE0 | 55.3% | ecx not kept across callee SHC_3BB0A8C1_0x004FAF70 | 0.0% | Pending From 3cc5cd87381c616c95b8127eaf8bca27f458ada7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:05 +0200 Subject: [PATCH 075/252] reimplement: SHC_3BB0A8C1_0x004F6C60 92.31% border index regalloc --- .../TileMapState/setupLogicalMapBorders.cpp | 48 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupLogicalMapBorders.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupLogicalMapBorders.cpp b/src/OpenSHC/Map/TileMapState/setupLogicalMapBorders.cpp new file mode 100644 index 000000000..f5d71273c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupLogicalMapBorders.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6C60 + void TileMapState::setupLogicalMapBorders() + { + int index = 0; + for (int rowWidth = 0; rowWidth < 400; rowWidth += 2) { + this->LogicLayer[index] = L_BORDER; + index++; + if (rowWidth > 0) { + this->LogicLayer[index] = L_BORDER_EDGE; + } + index = index + rowWidth; + if (rowWidth > 0) { + this->LogicLayer[index - 1] = L_BORDER_EDGE; + } + this->LogicLayer[index] = L_BORDER; + index++; + } + for (int rowWidth = 398; rowWidth >= 0; rowWidth -= 2) { + this->LogicLayer[index] = L_BORDER; + index++; + if (rowWidth > 0) { + this->LogicLayer[index] = L_BORDER_EDGE; + } + index = index + rowWidth; + if (rowWidth > 0) { + this->LogicLayer[index - 1] = L_BORDER_EDGE; + } + this->LogicLayer[index] = L_BORDER; + index++; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3759cabd0..b71839e66 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38745,7 +38745,7 @@ SHC_3BB0A8C1_0x004F6B20 | 0.0% | Pending SHC_3BB0A8C1_0x004F6C20 | 0.0% | Pending -SHC_3BB0A8C1_0x004F6C60 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6C60 | 92.3% | border index regalloc SHC_3BB0A8C1_0x004F6CF0 | 0.0% | Pending From 7e9e42503a5a2ccef3c82c30be7406c83995b5aa Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:06 +0200 Subject: [PATCH 076/252] reimplement: SHC_3BB0A8C1_0x00507060 90.76% setupBuildingData arg regalloc --- .../TileMapState/stampBuildingOntoTileMap.cpp | 47 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/stampBuildingOntoTileMap.cpp diff --git a/src/OpenSHC/Map/TileMapState/stampBuildingOntoTileMap.cpp b/src/OpenSHC/Map/TileMapState/stampBuildingOntoTileMap.cpp new file mode 100644 index 000000000..f97e85e83 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/stampBuildingOntoTileMap.cpp @@ -0,0 +1,47 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507060 + void TileMapState::stampBuildingOntoTileMap(int param_1, uint param_2, uint param_3, undefined4 param_4, + undefined4 param_5, uint param_6, undefined4 param_7, undefined4 param_8) + { + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, param_2, param_3, param_8, (BuildingType)(short)param_4, param_6, param_1, (short)param_5); + this->placedBuildingID = buildingID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_6); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + this->buildingX + param_2; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (byte)param_8; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b71839e66..19f141d33 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42093,7 +42093,7 @@ SHC_3BB0A8C1_0x00506E10 | 0.0% | Pending SHC_3BB0A8C1_0x00506F40 | 0.0% | Pending -SHC_3BB0A8C1_0x00507060 | 0.0% | Pending +SHC_3BB0A8C1_0x00507060 | 90.8% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00507130 | 0.0% | Pending From f2ce335cfb8088c7b3c39ad812cd17205eb1858a Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:34:06 +0200 Subject: [PATCH 077/252] reimplement: SHC_3BB0A8C1_0x004F8AC0 90.70% shr vs sar on logic bit --- ...HigherPlainNeighborWithWallOrGatehouse.cpp | 49 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/hasHigherPlainNeighborWithWallOrGatehouse.cpp diff --git a/src/OpenSHC/Map/TileMapState/hasHigherPlainNeighborWithWallOrGatehouse.cpp b/src/OpenSHC/Map/TileMapState/hasHigherPlainNeighborWithWallOrGatehouse.cpp new file mode 100644 index 000000000..f088cca28 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/hasHigherPlainNeighborWithWallOrGatehouse.cpp @@ -0,0 +1,49 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8AC0 + BOOLEnum TileMapState::hasHigherPlainNeighborWithWallOrGatehouse(int tile, int y, int direction) + { + int rotatedDirection = 0; + if (this->mapOrientation == 0) { + rotatedDirection = direction; + } else if (this->mapOrientation == 4) { + rotatedDirection = direction + 4; + } else if (this->mapOrientation == 2) { + rotatedDirection = direction + 2; + } else if (this->mapOrientation == 6) { + rotatedDirection = direction + 6; + } + if (rotatedDirection >= 8) { + rotatedDirection = rotatedDirection - 8; + } + + int neighbour = this->directionTranslationMatrix[y][rotatedDirection] + tile; + if (this->HeightLayer[tile] >= this->HeightLayer[neighbour]) { + return FALSE; + } + if ((this->LogicLayer[neighbour] & L_CRENEL) != 0) { + return FALSE; + } + if ((this->LogicLayer[neighbour] & L_STOCKPILEUnk) != 0) { + return FALSE; + } + return this->LogicLayer[neighbour] >> 8 & TRUE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 19f141d33..2de4a9d2d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39373,7 +39373,7 @@ SHC_3BB0A8C1_0x004F89C0 | 0.0% | Pending SHC_3BB0A8C1_0x004F8A40 | 87.2% | shr vs sar on logic bit -SHC_3BB0A8C1_0x004F8AC0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8AC0 | 90.7% | shr vs sar on logic bit SHC_3BB0A8C1_0x004F8B50 | 100.0% | Reimplemented From ec180cbe7213689d5a804f0a90baf813b4376686 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:40 +0200 Subject: [PATCH 078/252] reimplement: SHC_3BB0A8C1_0x00506D40 89.60% setupBuildingData arg regalloc --- .../TileMapState/placeSiegetowerPlaced.cpp | 50 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeSiegetowerPlaced.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeSiegetowerPlaced.cpp b/src/OpenSHC/Map/TileMapState/placeSiegetowerPlaced.cpp new file mode 100644 index 000000000..80b5873e9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeSiegetowerPlaced.cpp @@ -0,0 +1,50 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506D40 + void TileMapState::placeSiegetowerPlaced( + int param_1, uint param_2, uint param_3, undefined4 param_4, uint param_5, int param_6, undefined4 param_7) + { + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, param_2, param_3, param_7, (BuildingType)(short)param_4, param_5, param_1, param_6); + this->placedBuildingID = buildingID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_5); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + this->buildingX + param_2; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (byte)param_7; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_KEEP_NON_MANOR_HOUSE; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->BuildingWasLayer[tile] = (uchar)(short)param_4; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2de4a9d2d..09a9f2896 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42087,7 +42087,7 @@ SHC_3BB0A8C1_0x00506AD0 | 0.0% | Pending SHC_3BB0A8C1_0x00506BD0 | 0.0% | Pending -SHC_3BB0A8C1_0x00506D40 | 0.0% | Pending +SHC_3BB0A8C1_0x00506D40 | 89.6% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00506E10 | 0.0% | Pending From 8784abb9989f6056e8bcfff95b87bf6e55cdc284 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:40 +0200 Subject: [PATCH 079/252] reimplement: SHC_3BB0A8C1_0x004FAC70 84.71% ecx not kept across callee --- ...arBuildingFootprintAndRemoveSiegeTower.cpp | 62 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndRemoveSiegeTower.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndRemoveSiegeTower.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndRemoveSiegeTower.cpp new file mode 100644 index 000000000..8d13b1691 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndRemoveSiegeTower.cpp @@ -0,0 +1,62 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAC70 + void TileMapState::clearBuildingFootprintAndRemoveSiegeTower(int x, int y, int size) + { + int tileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(tileIndex, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_BUILDING | L_STAIRS | L_CRENEL_VARIATIONUnk + | L_KEEP_NON_MANOR_HOUSE); + this->BuildingLayer[tile] = 0; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)( + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile], tile); + short unitID = this->UnitLayer[tile]; + if (unitID != 0 && DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER) { + DAT_UnitsState::instance.units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } + tileIndex++; + } while (tileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 09a9f2896..def74c785 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40357,7 +40357,7 @@ SHC_3BB0A8C1_0x004FAAE0 | 0.0% | Pending SHC_3BB0A8C1_0x004FAB70 | 0.0% | Pending -SHC_3BB0A8C1_0x004FAC70 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAC70 | 84.7% | ecx not kept across callee SHC_3BB0A8C1_0x004FAD20 | 45.3% | ecx not kept across callee From 7873418edac07d230cef3c8b76be376ffe4b5667 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:40 +0200 Subject: [PATCH 080/252] reimplement: SHC_3BB0A8C1_0x005113F0 54.24% moat field reload/regalloc --- src/OpenSHC/Map/TileMapState/removeMoat.cpp | 51 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/removeMoat.cpp diff --git a/src/OpenSHC/Map/TileMapState/removeMoat.cpp b/src/OpenSHC/Map/TileMapState/removeMoat.cpp new file mode 100644 index 000000000..cff75b9b7 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/removeMoat.cpp @@ -0,0 +1,51 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005113F0 + BOOLEnum TileMapState::removeMoat(uint moatID, int param_2) + { + this->moats[moatID].fillProgress = this->moats[moatID].fillProgress - 1; + if ((char)this->moats[moatID].fillProgress >= 1) { + return FALSE; + } + + this->HeightLayer[this->moats[moatID].tile] = 8; + this->LogicLayer[this->moats[moatID].tile] = this->LogicLayer[this->moats[moatID].tile] & ~L_MOAT; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(2, this->moats[moatID].x, this->moats[moatID].y); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(this->moats[moatID].y, this->moats[moatID].tile); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + int tile = this->moats[moatID].tile; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatData, this)(moatID); + if (this->BuildingLayer[tile] != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateBuildingGraphicsLayer, this)( + this->BuildingLayer[tile]); + } + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + return TRUE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index def74c785..959b18020 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44181,7 +44181,7 @@ SHC_3BB0A8C1_0x005111D0 | 0.0% | Pending SHC_3BB0A8C1_0x00511240 | 0.0% | Pending -SHC_3BB0A8C1_0x005113F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005113F0 | 54.2% | moat field reload/regalloc SHC_3BB0A8C1_0x005114C0 | 0.0% | Pending From d146bb370645004760a607bec518f4c2bbab1888 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:41 +0200 Subject: [PATCH 081/252] reimplement: SHC_3BB0A8C1_0x00500500 86.54% moat field reload/regalloc --- .../TileMapState/advanceMoatDigProgress.cpp | 53 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/advanceMoatDigProgress.cpp diff --git a/src/OpenSHC/Map/TileMapState/advanceMoatDigProgress.cpp b/src/OpenSHC/Map/TileMapState/advanceMoatDigProgress.cpp new file mode 100644 index 000000000..8d03dbb10 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/advanceMoatDigProgress.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" + +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500500 + undefined4 TileMapState::advanceMoatDigProgress(int moatID) + { + this->moats[moatID].fillProgress = this->moats[moatID].fillProgress + 1; + if ((char)this->moats[moatID].fillProgress <= 3) { + return 0; + } + + int tile = this->moats[moatID].tile; + this->moats[moatID].someCountDown = 0; + this->moats[moatID].fillProgress = 4; + this->moats[moatID].stage = 2; + this->HeightLayer[tile] = 0; + this->LogicLayer[this->moats[moatID].tile] + = this->LogicLayer[this->moats[moatID].tile] & ~L_MOAT_DUG_OR_PLANNED; + this->LogicLayer[this->moats[moatID].tile] = this->LogicLayer[this->moats[moatID].tile] & ~L_PLAIN2_AND_PITCH; + this->LogicLayer[this->moats[moatID].tile] = this->LogicLayer[this->moats[moatID].tile] | L_MOAT; + this->Logic2Layer[this->moats[moatID].tile] = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(2, this->moats[moatID].x, this->moats[moatID].y); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(this->moats[moatID].y, this->moats[moatID].tile); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + return 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 959b18020..adcdd189a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41439,7 +41439,7 @@ SHC_3BB0A8C1_0x00500370 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005003D0 | 0.0% | Pending -SHC_3BB0A8C1_0x00500500 | 0.0% | Pending +SHC_3BB0A8C1_0x00500500 | 86.5% | moat field reload/regalloc SHC_3BB0A8C1_0x005005F0 | 100.0% | Reimplemented From cbf8a976f28f53549545fe9a2120223f6e97c1e7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:41 +0200 Subject: [PATCH 082/252] reimplement: SHC_3BB0A8C1_0x004F93E0 49.02% const 1 rematerialised --- .../Map/TileMapState/destroyWallsOfPlayer.cpp | 60 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/destroyWallsOfPlayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/destroyWallsOfPlayer.cpp b/src/OpenSHC/Map/TileMapState/destroyWallsOfPlayer.cpp new file mode 100644 index 000000000..f17e32f42 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/destroyWallsOfPlayer.cpp @@ -0,0 +1,60 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F93E0 + void TileMapState::destroyWallsOfPlayer(int playerID) + { + for (int tile = 0; tile < 80400; tile++) { + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + continue; + } + if ((this->WallOwnerLayer[tile] & 7) + 1 != playerID) { + continue; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, DAT_EntityState::ptr)( + tile); + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_STAIRS | L_UNKNOWN_WALL_RELATED | L_CRENEL_VARIATIONUnk); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->DamageLayer[tile] = 0; + uint y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + int rowTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(7, tile - rowTile, y); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index adcdd189a..01508b538 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39383,7 +39383,7 @@ SHC_3BB0A8C1_0x004F9000 | 0.0% | Pending SHC_3BB0A8C1_0x004F9220 | 0.0% | Pending -SHC_3BB0A8C1_0x004F93E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F93E0 | 49.0% | const 1 rematerialised SHC_3BB0A8C1_0x004F94A0 | 0.0% | Pending From 27b89b4437939f8b11f90827c02d3aa24f0c48ad Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:41 +0200 Subject: [PATCH 083/252] reimplement: SHC_3BB0A8C1_0x005003D0 54.34% moat row walk regalloc --- .../Map/TileMapState/setXYBasedOnMoatID.cpp | 57 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setXYBasedOnMoatID.cpp diff --git a/src/OpenSHC/Map/TileMapState/setXYBasedOnMoatID.cpp b/src/OpenSHC/Map/TileMapState/setXYBasedOnMoatID.cpp new file mode 100644 index 000000000..761e2be5c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setXYBasedOnMoatID.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005003D0 + int TileMapState::setXYBasedOnMoatID(int moatID, int param_2, uint x, uint y) + { + if (x > 399 || y > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0; + } + + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + if (param_2 == 1) { + this->ALG_MoatXResult = this->moats[moatID].x; + this->ALG_MoatYResult = this->moats[moatID].y; + return DAT_ViewportRenderState::instance.translationMatrix[this->ALG_MoatYResult].addXgetTile + + this->ALG_MoatXResult; + } + if (param_2 != 2) { + return 0; + } + + for (int direction = 0; direction < 8; direction++) { + int neighbour + = this->directionTranslationMatrix[this->moats[moatID].y][direction] + this->moats[moatID].tile; + if ((uint)(this->HeightLayer[tile] + 0x10) < (uint)this->HeightLayer[neighbour]) { + continue; + } + if (this->PathConnectionLayer[neighbour] != this->PathConnectionLayer[tile]) { + continue; + } + + this->someMoatTile = this->moats[moatID].tile; + this->ALG_MoatXResult = this->moats[moatID].x + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction].int_.xOffset; + this->ALG_MoatYResult = this->moats[moatID].y + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction].int_.yOffset; + return neighbour; + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 01508b538..d3e10917f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41437,7 +41437,7 @@ SHC_3BB0A8C1_0x00500310 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500370 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005003D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005003D0 | 54.3% | moat row walk regalloc SHC_3BB0A8C1_0x00500500 | 86.5% | moat field reload/regalloc From e9e56814e784e6cc098d3d68276a68d97db27f40 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:42 +0200 Subject: [PATCH 084/252] reimplement: SHC_3BB0A8C1_0x004F9980 34.23% ecx not kept across callee --- .../storeMinAndMaxHeightOfArea.cpp | 50 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp diff --git a/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp b/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp new file mode 100644 index 000000000..448f643c5 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp @@ -0,0 +1,50 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9980 + void TileMapState::storeMinAndMaxHeightOfArea(uint x, uint y, int buildingWidthAndHeight) + { + this->buildingMinHeight = 1000; + this->buildingMaxHeight = 0; + if (x > 399 || y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, buildingWidthAndHeight); + uint footprintY = this->buildingY + y; + if (this->buildingX + x <= 399 && footprintY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[footprintY * 400 + this->buildingX + x] + != 0) { + uint height + = this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[footprintY].addXgetTile + + this->buildingX + x]; + if ((int)height > (int)this->buildingMaxHeight) { + this->buildingMaxHeight = height; + } + if ((int)height < (int)this->buildingMinHeight) { + this->buildingMinHeight = height; + } + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d3e10917f..7a2633ab5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39409,7 +39409,7 @@ SHC_3BB0A8C1_0x004F9924 | 0.0% | Pending SHC_3BB0A8C1_0x004F9930 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F9980 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9980 | 34.2% | ecx not kept across callee SHC_3BB0A8C1_0x004F99D0 | 0.0% | Pending From 2ac998a1ad33976d4ab2e325edf1b5f983eaeecc Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:42 +0200 Subject: [PATCH 085/252] reimplement: SHC_3BB0A8C1_0x00507280 54.55% ecx not kept across callee --- .../TileMapState/upgradeTowerLogicLayer.cpp | 58 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/upgradeTowerLogicLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/upgradeTowerLogicLayer.cpp b/src/OpenSHC/Map/TileMapState/upgradeTowerLogicLayer.cpp new file mode 100644 index 000000000..c86f728e7 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/upgradeTowerLogicLayer.cpp @@ -0,0 +1,58 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507280 + void TileMapState::upgradeTowerLogicLayer(int buildingID) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight); + int tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[buildingID].y + this->buildingY] + .addXgetTile + + DAT_BuildingsState::instance.buildings[buildingID].x + this->buildingX; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BUILDING; + uint widthOrHeight = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + uint logic = this->LogicLayer[tile]; + if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[widthOrHeight][0] == buildingSizeTileIndex) { + logic = logic | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[widthOrHeight][1] + == buildingSizeTileIndex) { + logic = logic | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[widthOrHeight][2] + == buildingSizeTileIndex) { + logic = logic | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[widthOrHeight][3] + == buildingSizeTileIndex) { + logic = logic | L_BUILDING; + } else { + logic = logic | L_KEEP_NON_MANOR_HOUSE; + } + buildingSizeTileIndex++; + this->LogicLayer[tile] = logic; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7a2633ab5..bfb3da62b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42097,7 +42097,7 @@ SHC_3BB0A8C1_0x00507060 | 90.8% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00507130 | 0.0% | Pending -SHC_3BB0A8C1_0x00507280 | 0.0% | Pending +SHC_3BB0A8C1_0x00507280 | 54.5% | ecx not kept across callee SHC_3BB0A8C1_0x00507350 | 0.0% | Pending From 2b028b5b7b17336cd22a5ef0bce4278589dfee60 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:42 +0200 Subject: [PATCH 086/252] reimplement: SHC_3BB0A8C1_0x004F89C0 59.15% orientation blocks not shared --- .../getWallFlagForOrientedDirection.cpp | 40 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getWallFlagForOrientedDirection.cpp diff --git a/src/OpenSHC/Map/TileMapState/getWallFlagForOrientedDirection.cpp b/src/OpenSHC/Map/TileMapState/getWallFlagForOrientedDirection.cpp new file mode 100644 index 000000000..9cb0eaacd --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getWallFlagForOrientedDirection.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F89C0 + uint TileMapState::getWallFlagForOrientedDirection(int tile, int y, int twoOrFour) + { + int direction = 0; + if (twoOrFour == 2) { + if (this->mapOrientation == 0) { + direction = 2; + } else if (this->mapOrientation == 2) { + direction = 4; + } else if (this->mapOrientation == 4) { + direction = 6; + } + } else { + if (twoOrFour != 4) { + return 0; + } + if (this->mapOrientation == 0) { + direction = 4; + } else if (this->mapOrientation == 2) { + direction = 6; + } else if (this->mapOrientation == 6) { + direction = 2; + } + } + return this->LogicLayer[this->directionTranslationMatrix[y][direction] + tile] >> 8 & 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bfb3da62b..ef9e61c9d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39369,7 +39369,7 @@ SHC_3BB0A8C1_0x004F8840 | 0.0% | Pending SHC_3BB0A8C1_0x004F8900 | 0.0% | Pending -SHC_3BB0A8C1_0x004F89C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F89C0 | 59.1% | orientation blocks not shared SHC_3BB0A8C1_0x004F8A40 | 87.2% | shr vs sar on logic bit From 8469789987f617754d4d9bfcc46d543685e89bb5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:43 +0200 Subject: [PATCH 087/252] reimplement: SHC_3BB0A8C1_0x004F8840 93.65% direction chain order --- .../isWallConnectionHeightValid.cpp | 65 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isWallConnectionHeightValid.cpp diff --git a/src/OpenSHC/Map/TileMapState/isWallConnectionHeightValid.cpp b/src/OpenSHC/Map/TileMapState/isWallConnectionHeightValid.cpp new file mode 100644 index 000000000..d9cf431a0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isWallConnectionHeightValid.cpp @@ -0,0 +1,65 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8840 + BOOLEnum TileMapState::isWallConnectionHeightValid(int tile, int y, int param_3) + { + int tileHeight = this->HeightLayer[tile]; + int firstDirection = 0; + int secondDirection = 0; + if (param_3 == 0) { + secondDirection = 4; + } else if (param_3 == 2) { + firstDirection = 2; + secondDirection = 6; + } else if (param_3 == 4) { + secondDirection = param_3; + } else if (param_3 == 6) { + firstDirection = 2; + secondDirection = 6; + } + + int first = this->directionTranslationMatrix[y][firstDirection] + tile; + if ((this->LogicLayer[first] & L_WALL_OR_GATEHOUSE) == 0) { + return FALSE; + } + if ((this->LogicLayer[first] & L_STOCKPILEUnk) != 0) { + return FALSE; + } + int minHeight = tileHeight - 0x10; + if (this->HeightLayer[first] < minHeight && this->DamageLayer[first] == 0) { + return FALSE; + } + + int second = this->directionTranslationMatrix[y][secondDirection] + tile; + if ((this->LogicLayer[second] & L_WALL_OR_GATEHOUSE) == 0) { + return FALSE; + } + if ((this->LogicLayer[second] & L_STOCKPILEUnk) != 0) { + return FALSE; + } + if (this->HeightLayer[second] < minHeight && this->DamageLayer[second] == 0) { + return FALSE; + } + return TRUE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ef9e61c9d..d67b93af8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39365,7 +39365,7 @@ SHC_3BB0A8C1_0x004F86D0 | 0.0% | Pending SHC_3BB0A8C1_0x004F8780 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8840 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8840 | 93.7% | direction chain order SHC_3BB0A8C1_0x004F8900 | 0.0% | Pending From 799ae9334480fce9cbf2d3583b9c88ebe73fd219 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:43 +0200 Subject: [PATCH 088/252] reimplement: SHC_3BB0A8C1_0x00507350 74.14% tree switch jump table --- .../TileMapState/resetTileAndClearMoat.cpp | 77 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetTileAndClearMoat.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetTileAndClearMoat.cpp b/src/OpenSHC/Map/TileMapState/resetTileAndClearMoat.cpp new file mode 100644 index 000000000..63b7c6780 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetTileAndClearMoat.cpp @@ -0,0 +1,77 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507350 + void TileMapState::resetTileAndClearMoat(int tile) + { + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int rowTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_PLAIN2_AND_PITCH | L_WALL_OR_GATEHOUSE | L_CRENEL | L_STAIRS | L_UNKNOWN_WALL_RELATED + | L_CRENEL_VARIATIONUnk); + this->HeightLayer[tile] = DAT_TileMapState::instance.DefaultHeightLayer[tile]; + this->DamageLayer[tile] = 0; + if ((this->LogicLayer[tile] & L_TREE) != 0) { + int treeID = this->OrganismLayer[tile]; + if (treeID < 2000) { + switch (DAT_LandscapeState::instance.trees[treeID].treeType) { + case (TreeType)5: + case (TreeType)6: + case (TreeType)7: + case (TreeType)8: + case (TreeType)9: + case (TreeType)10: + case (TreeType)11: + case (TreeType)12: + case (TreeType)13: + case (TreeType)14: + case (TreeType)16: + case (TreeType)17: + case (TreeType)18: + case (TreeType)19: + DAT_LandscapeState::instance.trees[treeID].state = 3; + } + } + } + if ((this->LogicLayer[tile] & (L_MOAT | L_MOAT_DUG_OR_PLANNED)) != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(tile - rowTile, y); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_MOAT | L_MOAT_DUG_OR_PLANNED); + } + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfc3f; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d67b93af8..b9eaefbad 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42099,7 +42099,7 @@ SHC_3BB0A8C1_0x00507130 | 0.0% | Pending SHC_3BB0A8C1_0x00507280 | 54.5% | ecx not kept across callee -SHC_3BB0A8C1_0x00507350 | 0.0% | Pending +SHC_3BB0A8C1_0x00507350 | 74.1% | tree switch jump table SHC_3BB0A8C1_0x00507408 | 0.0% | Pending From 357df4df3693483a47212f74282fef64782df7d6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 01:49:43 +0200 Subject: [PATCH 089/252] reimplement: SHC_3BB0A8C1_0x004FB3F0 34.33% XYPair stride regalloc --- .../spawnFloatingNumberAroundTile.cpp | 49 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/spawnFloatingNumberAroundTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/spawnFloatingNumberAroundTile.cpp b/src/OpenSHC/Map/TileMapState/spawnFloatingNumberAroundTile.cpp new file mode 100644 index 000000000..171b352c0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/spawnFloatingNumberAroundTile.cpp @@ -0,0 +1,49 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/IO/Graphics/GmID.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB3F0 + void TileMapState::spawnFloatingNumberAroundTile(int x, int y, int type) + { + int radius = type / 2; + int xOffset = DAT_TerrainDefinedData::instance.field2474_0x2764[radius * 60].x; + if (xOffset == -1) { + return; + } + + uint index = 0; + do { + int yOffset = DAT_TerrainDefinedData::instance.field2474_0x2764[radius * 60 + index].y; + int tile = DAT_ViewportRenderState::instance.translationMatrix[yOffset + (y - radius)].addXgetTile + xOffset + + (x - radius); + if ((this->LogicLayer[tile] & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 + && (index & 1) == 0) { + uint frame + = (this->field161_0x5549c0 + yOffset + xOffset + index + (x - radius) - 1 + (y - radius)) % 16; + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::createFloatingLayerElement, + DAT_ViewportRenderState::ptr)( + OpenSHC::IO::Graphics::GID_FLOATS_NEW, frame + 0xe5, 16, 14, tile, 0x100021); + } + index++; + xOffset = DAT_TerrainDefinedData::instance.field2474_0x2764[radius * 60 + index].x; + } while (xOffset != -1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b9eaefbad..e5c480e53 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40567,7 +40567,7 @@ SHC_3BB0A8C1_0x004FB358 | 0.0% | Pending SHC_3BB0A8C1_0x004FB360 | 79.0% | ecx not kept across callee -SHC_3BB0A8C1_0x004FB3F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB3F0 | 34.3% | XYPair stride regalloc SHC_3BB0A8C1_0x004FB4D0 | 0.0% | Pending From a1db33a6a0718ecb26e9f9ed8350a15fb5056244 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:29 +0200 Subject: [PATCH 090/252] reimplement: SHC_3BB0A8C1_0x00515C80 52.56% ecx not kept across callee --- .../TileMapState/createWaterForDrawBridge.cpp | 53 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/createWaterForDrawBridge.cpp diff --git a/src/OpenSHC/Map/TileMapState/createWaterForDrawBridge.cpp b/src/OpenSHC/Map/TileMapState/createWaterForDrawBridge.cpp new file mode 100644 index 000000000..ac39768a7 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/createWaterForDrawBridge.cpp @@ -0,0 +1,53 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00515C80 + void TileMapState::createWaterForDrawBridge(int buildingID) + { + uint xPosition = DAT_BuildingsState::instance.buildings[buildingID].x; + uint widthOrHeight = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + uint yPosition = DAT_BuildingsState::instance.buildings[buildingID].y; + int variation = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation / 2; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 5); + uint footprintY = yPosition + this->buildingY; + int tile = DAT_ViewportRenderState::instance.translationMatrix[footprintY].addXgetTile + this->buildingX + + xPosition; + if (DAT_TerrainDefinedData::instance.DrawbridgeOrientationMapping[variation][buildingSizeTileIndex] != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::createMoatData, this)( + DAT_BuildingsState::instance.buildings[buildingID].owner, this->buildingX + xPosition, footprintY, + 1); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMoatVisualStateAtTile, this)(tile, 0); + this->HeightLayer[tile] = 0; + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateBuildingGraphicsLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(widthOrHeight + 6, xPosition, yPosition); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e5c480e53..a7651ab04 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44769,7 +44769,7 @@ SHC_3BB0A8C1_0x00515740 | 0.0% | Pending SHC_3BB0A8C1_0x00515A20 | 0.0% | Pending -SHC_3BB0A8C1_0x00515C80 | 0.0% | Pending +SHC_3BB0A8C1_0x00515C80 | 52.6% | ecx not kept across callee SHC_3BB0A8C1_0x00515DA0 | 0.0% | Pending From 08cd23084ab554c3230535e0ab627339a33b6585 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:29 +0200 Subject: [PATCH 091/252] reimplement: SHC_3BB0A8C1_0x004F8900 63.49% neighbour load regalloc --- .../hasOnlyTowerNeighborsNoWalls.cpp | 50 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/hasOnlyTowerNeighborsNoWalls.cpp diff --git a/src/OpenSHC/Map/TileMapState/hasOnlyTowerNeighborsNoWalls.cpp b/src/OpenSHC/Map/TileMapState/hasOnlyTowerNeighborsNoWalls.cpp new file mode 100644 index 000000000..51a2697ad --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/hasOnlyTowerNeighborsNoWalls.cpp @@ -0,0 +1,50 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8900 + BOOLEnum TileMapState::hasOnlyTowerNeighborsNoWalls(int tile, int y) + { + int unknownWallRelated = 0; + int wallOrGatehouse = 0; + if ((this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & L_UNKNOWN_WALL_RELATED) != 0) { + unknownWallRelated++; + } else if ((this->LogicLayer[this->directionTranslationMatrix[y][0] + tile] & L_WALL_OR_GATEHOUSE) != 0) { + wallOrGatehouse++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & L_UNKNOWN_WALL_RELATED) != 0) { + unknownWallRelated++; + } else if ((this->LogicLayer[this->directionTranslationMatrix[y][2] + tile] & L_WALL_OR_GATEHOUSE) != 0) { + wallOrGatehouse++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & L_UNKNOWN_WALL_RELATED) != 0) { + unknownWallRelated++; + } else if ((this->LogicLayer[this->directionTranslationMatrix[y][4] + tile] & L_WALL_OR_GATEHOUSE) != 0) { + wallOrGatehouse++; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & L_UNKNOWN_WALL_RELATED) != 0) { + unknownWallRelated++; + } else if ((this->LogicLayer[this->directionTranslationMatrix[y][6] + tile] & L_WALL_OR_GATEHOUSE) != 0) { + wallOrGatehouse++; + } + if (unknownWallRelated != 0 && wallOrGatehouse == 0) { + return TRUE; + } + return FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a7651ab04..90322e919 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39367,7 +39367,7 @@ SHC_3BB0A8C1_0x004F8780 | 0.0% | Pending SHC_3BB0A8C1_0x004F8840 | 93.7% | direction chain order -SHC_3BB0A8C1_0x004F8900 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8900 | 63.5% | neighbour load regalloc SHC_3BB0A8C1_0x004F89C0 | 59.1% | orientation blocks not shared From c53a9fce08e35082a4916c1fb04c2e17cec219a5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:29 +0200 Subject: [PATCH 092/252] reimplement: SHC_3BB0A8C1_0x004F86D0 98.39% direction chain regalloc --- .../isWallCornerForCardinalDirection.cpp | 59 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isWallCornerForCardinalDirection.cpp diff --git a/src/OpenSHC/Map/TileMapState/isWallCornerForCardinalDirection.cpp b/src/OpenSHC/Map/TileMapState/isWallCornerForCardinalDirection.cpp new file mode 100644 index 000000000..8a5e8f66b --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isWallCornerForCardinalDirection.cpp @@ -0,0 +1,59 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F86D0 + BOOLEnum TileMapState::isWallCornerForCardinalDirection(int tile, int y, int direction) + { + int first = 0; + int second = 0; + int third = 0; + int fourth = 0; + if (direction == 0) { + first = 0; + second = 4; + third = 2; + fourth = 6; + } else if (direction == 2) { + first = 2; + second = 6; + third = 0; + fourth = 4; + } else if (direction == 4) { + first = 0; + second = 4; + third = 2; + fourth = 6; + } else if (direction == 6) { + first = 2; + second = 6; + third = 0; + fourth = 4; + } + + if ((this->LogicLayer[this->directionTranslationMatrix[y][first] + tile] & L_CRENEL) == 0) { + return FALSE; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][second] + tile] & L_CRENEL) == 0) { + return FALSE; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][third] + tile] & L_CRENEL) != 0) { + return FALSE; + } + return ~(this->LogicLayer[this->directionTranslationMatrix[y][fourth] + tile] >> 9) & TRUE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 90322e919..c2b0e66cf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39361,7 +39361,7 @@ SHC_3BB0A8C1_0x004F85B0 | 41.0% | regalloc: extra edi SHC_3BB0A8C1_0x004F8640 | 40.0% | regalloc: extra edi -SHC_3BB0A8C1_0x004F86D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F86D0 | 98.4% | direction chain regalloc SHC_3BB0A8C1_0x004F8780 | 0.0% | Pending From 567a48b535a2bf3dc6361ddccd4adfdacee500ad Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:30 +0200 Subject: [PATCH 093/252] reimplement: SHC_3BB0A8C1_0x004FAD70 77.67% ecx not kept across callee --- .../clearBuildingFootprintWithEdgeRubble.cpp | 59 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingFootprintWithEdgeRubble.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingFootprintWithEdgeRubble.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintWithEdgeRubble.cpp new file mode 100644 index 000000000..348bc685b --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintWithEdgeRubble.cpp @@ -0,0 +1,59 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAD70 + void TileMapState::clearBuildingFootprintWithEdgeRubble(int x, int y, int size) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_BUILDING | L_STAIRS | L_CRENEL_VARIATIONUnk + | L_KEEP_NON_MANOR_HOUSE); + if ((this->MiscDisplayLayer[tile] & 0x20) != 0) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffdf; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + } + short buildingID = this->BuildingLayer[tile]; + this->BuildingLayer[tile] = 0; + if (DAT_BuildingsState::instance.buildings[buildingID].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isFootprintIndexOnEdge, this)( + buildingSizeTileIndex, size) + == FALSE) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x2000; + } + buildingSizeTileIndex++; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c2b0e66cf..1e979b31a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40361,7 +40361,7 @@ SHC_3BB0A8C1_0x004FAC70 | 84.7% | ecx not kept across callee SHC_3BB0A8C1_0x004FAD20 | 45.3% | ecx not kept across callee -SHC_3BB0A8C1_0x004FAD70 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAD70 | 77.7% | ecx not kept across callee SHC_3BB0A8C1_0x004FAE50 | 35.1% | ecx not kept across callee From ad6a7f8f499310cae59dfa61b8f738d4fdd5b7cb Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:30 +0200 Subject: [PATCH 094/252] reimplement: SHC_3BB0A8C1_0x00508910 66.67% ecx not kept across callee --- .../floodMoatUnderRemovedBuilding.cpp | 52 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/floodMoatUnderRemovedBuilding.cpp diff --git a/src/OpenSHC/Map/TileMapState/floodMoatUnderRemovedBuilding.cpp b/src/OpenSHC/Map/TileMapState/floodMoatUnderRemovedBuilding.cpp new file mode 100644 index 000000000..ac60813f8 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/floodMoatUnderRemovedBuilding.cpp @@ -0,0 +1,52 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508910 + void TileMapState::floodMoatUnderRemovedBuilding(int buildingID) + { + uint yPosition = DAT_BuildingsState::instance.buildings[buildingID].y; + uint xPosition = DAT_BuildingsState::instance.buildings[buildingID].x; + uint widthOrHeight = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + int variation = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation / 2; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 5); + int targetedTile + = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + yPosition].addXgetTile + + this->buildingX + xPosition; + if (DAT_TerrainDefinedData::instance.DrawbridgeOrientationMapping[variation][buildingSizeTileIndex] != 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(targetedTile) + != 0) { + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] | L_MOAT; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMoatVisualStateAtTile, this)(targetedTile, 2); + } + } + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateBuildingGraphicsLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(widthOrHeight + 6, xPosition, yPosition); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1e979b31a..0a4bef78f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42163,7 +42163,7 @@ SHC_3BB0A8C1_0x00508760 | 0.0% | Pending SHC_3BB0A8C1_0x00508870 | 88.9% | Style pass, asm differs -SHC_3BB0A8C1_0x00508910 | 0.0% | Pending +SHC_3BB0A8C1_0x00508910 | 66.7% | ecx not kept across callee SHC_3BB0A8C1_0x00508A00 | 0.0% | Pending From 27cba7e374950dd1d7191aaa5ce7e245925232bd Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:30 +0200 Subject: [PATCH 095/252] reimplement: SHC_3BB0A8C1_0x004F8210 94.66% switch table vs compare chain --- .../Map/TileMapState/getBuildingHurtSFXID.cpp | 62 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getBuildingHurtSFXID.cpp diff --git a/src/OpenSHC/Map/TileMapState/getBuildingHurtSFXID.cpp b/src/OpenSHC/Map/TileMapState/getBuildingHurtSFXID.cpp new file mode 100644 index 000000000..6e090a705 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getBuildingHurtSFXID.cpp @@ -0,0 +1,62 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingLogicalState; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8210 + uint TileMapState::getBuildingHurtSFXID(int tile) + { + short buildingID = this->BuildingLayer[tile]; + if (buildingID == 0) { + return this->LogicLayer[tile] >> 7 & 2; + } + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == 0) { + return 0; + } + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == OpenSHC::Map::Buildings::BLS_REMOVE) { + return 0; + } + if (DAT_BuildingsState::instance.buildings[buildingID].currentHealth == 0) { + return 0; + } + + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_BARRACKS: + case OpenSHC::Map::Buildings::BT_STOCKPILE: + case OpenSHC::Map::Buildings::BT_ARMORY: + case OpenSHC::Map::Buildings::BT_ENGINEERSGUILD: + case OpenSHC::Map::Buildings::BT_TUNNELERSGUILD: + case OpenSHC::Map::Buildings::BT_CHAPEL: + case OpenSHC::Map::Buildings::BT_CHURCH: + case OpenSHC::Map::Buildings::BT_CATHEDRAL: + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_GATEHOUSE: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + case OpenSHC::Map::Buildings::BT_OUTPOST_EUROPEAN: + return 2; + default: + return 1; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0a4bef78f..4fcad3434 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38793,7 +38793,7 @@ SHC_3BB0A8C1_0x004F8160 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F81D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F8210 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8210 | 94.7% | switch table vs compare chain SHC_3BB0A8C1_0x004F8288 | 0.0% | Pending From ce7e27b2cd5a606ea8d6f53952a9bfe0ce18d902 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:31 +0200 Subject: [PATCH 096/252] reimplement: SHC_3BB0A8C1_0x004F94A0 67.23% logic masks merged by cl --- .../validateWallPlacementAtTile.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/validateWallPlacementAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/validateWallPlacementAtTile.cpp b/src/OpenSHC/Map/TileMapState/validateWallPlacementAtTile.cpp new file mode 100644 index 000000000..38e2bd608 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/validateWallPlacementAtTile.cpp @@ -0,0 +1,74 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F94A0 + void TileMapState::validateWallPlacementAtTile(int playerID, uint x, uint y, MappersEnum param_4) + { + this->illegalBuild = TRUE; + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + uint logic = this->LogicLayer[tile]; + if ((logic & L_WALL_OR_GATEHOUSE) != 0 && (char)this->DamageLayer[tile] <= 11) { + return; + } + if ((logic & L_BUILDING) != 0) { + return; + } + if (this->BuildingLayer[tile] != 0) { + return; + } + if ((logic & (L_PLAIN1_AND_FARM | L_BORDER)) != 0) { + return; + } + if ((logic & (L_SEA | L_ROCKY | L_RIVER | L_FORD | L_MARSH | L_MOAT)) != 0) { + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, x, y, 5) + != FALSE) { + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findSomeSuitableLocationUnk, + DAT_PathFindingState::ptr)(playerID, x, y, 2) + != 0) { + return; + } + + if (this->UnitLayer[tile] != 0 && (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0 + && ((undefined2)param_4 == OpenSHC::Commands::M_MAPPER_CRENAL + || (undefined2)param_4 == OpenSHC::Commands::M_MAPPER_CRENAL2)) { + DAT_UnitsState::instance.units[(short)this->UnitLayer[tile]].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + } + this->illegalBuild = FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4fcad3434..9168ddc3b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39385,7 +39385,7 @@ SHC_3BB0A8C1_0x004F9220 | 0.0% | Pending SHC_3BB0A8C1_0x004F93E0 | 49.0% | const 1 rematerialised -SHC_3BB0A8C1_0x004F94A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F94A0 | 67.2% | logic masks merged by cl SHC_3BB0A8C1_0x004F9590 | 0.0% | Pending From 27dcba45ad5178001a6a0f982c00d6f5900efe2c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:31 +0200 Subject: [PATCH 097/252] reimplement: SHC_3BB0A8C1_0x004F8780 100.00% Reimplemented --- .../isWallCornerForDiagonalDirection.cpp | 56 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isWallCornerForDiagonalDirection.cpp diff --git a/src/OpenSHC/Map/TileMapState/isWallCornerForDiagonalDirection.cpp b/src/OpenSHC/Map/TileMapState/isWallCornerForDiagonalDirection.cpp new file mode 100644 index 000000000..12f19fe77 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isWallCornerForDiagonalDirection.cpp @@ -0,0 +1,56 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8780 + uint TileMapState::isWallCornerForDiagonalDirection(int tile, int y, int direction) + { + int first = 0; + int second = 0; + int third = 0; + int fourth = 0; + if (direction == 1) { + first = 4; + second = 6; + third = 0; + fourth = 2; + } else if (direction == 3) { + first = 0; + second = 6; + third = 4; + fourth = 2; + } else if (direction == 5) { + first = 0; + second = 2; + third = 4; + fourth = 6; + } else if (direction == 7) { + first = 4; + second = 2; + third = 0; + fourth = 6; + } + + if ((this->LogicLayer[this->directionTranslationMatrix[y][first] + tile] & L_CRENEL) == 0) { + return 0; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][second] + tile] & L_CRENEL) == 0) { + return 0; + } + if ((this->LogicLayer[this->directionTranslationMatrix[y][third] + tile] & L_CRENEL) != 0) { + return 0; + } + return ~((uint)this->LogicLayer[this->directionTranslationMatrix[y][fourth] + tile] >> 9) & 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9168ddc3b..303334dce 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39363,7 +39363,7 @@ SHC_3BB0A8C1_0x004F8640 | 40.0% | regalloc: extra edi SHC_3BB0A8C1_0x004F86D0 | 98.4% | direction chain regalloc -SHC_3BB0A8C1_0x004F8780 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8780 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F8840 | 93.7% | direction chain order From 71c67fd6d3349b4b6c547f3d48ff5e339e5a5994 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:31 +0200 Subject: [PATCH 098/252] reimplement: SHC_3BB0A8C1_0x004FF870 8.93% original built unoptimised --- ...BitFlagBasedOnWallTowerGatehouseOrKeep.cpp | 64 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp diff --git a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp new file mode 100644 index 000000000..21d6a0bf8 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp @@ -0,0 +1,64 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Restarted to delay deadcode elimination for space: ram + */ + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FF870 + byte TileMapState::setBitFlagBasedOnWallTowerGatehouseOrKeep(int x, int y) + { + this->DAT_SomeY = y; + this->DAT_SomeTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, DAT_ViewportRenderState::ptr)(x, y); + this->bitFlag = 0; + if ((((uint*)this->ptr_LogicLayer)[this->DAT_SomeTile + 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) + != 0) { + this->bitFlag = 0x20; + } + if ((((uint*)this->ptr_LogicLayer)[this->DAT_SomeTile - 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + + uint* northRow = (uint*)this->ptr_LogicLayer + this->DAT_SomeTile + + ((int*)this->ptr_MovementDirectionTranslationMatrix)[this->DAT_SomeY * 8]; + if ((northRow[-1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 1; + } + if ((northRow[1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 0x40; + } + if ((*northRow & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + + uint* southRow = (uint*)this->ptr_LogicLayer + this->DAT_SomeTile + + ((int*)this->ptr_MovementDirectionTranslationMatrix)[this->DAT_SomeY * 8 + 4]; + if ((southRow[-1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 4; + } + if ((southRow[1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 0x10; + } + if ((*southRow & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = this->bitFlag | 8; + } + return this->bitFlag; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 303334dce..883e05366 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41103,7 +41103,7 @@ SHC_3BB0A8C1_0x004FF080 | 0.0% | Pending SHC_3BB0A8C1_0x004FF420 | 0.0% | Pending -SHC_3BB0A8C1_0x004FF870 | 0.0% | Pending +SHC_3BB0A8C1_0x004FF870 | 8.9% | original built unoptimised SHC_3BB0A8C1_0x004FF990 | 0.0% | Pending From 734eabc0d4b44f1cce670ac93b5927b502936603 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:32 +0200 Subject: [PATCH 099/252] reimplement: SHC_3BB0A8C1_0x00508760 69.03% ecx not kept across callee --- ...clearSizeFiveBuildingFootprintAndMoats.cpp | 60 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearSizeFiveBuildingFootprintAndMoats.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearSizeFiveBuildingFootprintAndMoats.cpp b/src/OpenSHC/Map/TileMapState/clearSizeFiveBuildingFootprintAndMoats.cpp new file mode 100644 index 000000000..1d87c3ef0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearSizeFiveBuildingFootprintAndMoats.cpp @@ -0,0 +1,60 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_MOAT; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508760 + void TileMapState::clearSizeFiveBuildingFootprintAndMoats(int x, int y) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, 5); + int targetedTile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + short buildingID = this->BuildingLayer[targetedTile]; + short variation = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation; + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] & ~L_BUILDING; + if (DAT_TerrainDefinedData::instance.DrawbridgeOrientationMapping[variation / 2][buildingSizeTileIndex] + != 0) { + uint moatID + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(targetedTile); + if (moatID != 0) { + if (DAT_BuildingsState::instance.buildings[buildingID].noRubble == 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatData, this)(moatID); + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] & ~L_MOAT; + this->Logic2Layer[targetedTile] = this->Logic2Layer[targetedTile] | L2_EARTH_AND_STONES; + this->BuildingWasLayer[targetedTile] = 0; + this->HeightLayer[targetedTile] = 8; + } else { + this->LogicLayer[targetedTile] = this->LogicLayer[targetedTile] | L_MOAT; + } + } + } + if ((this->LogicLayer[targetedTile] & L_MOAT) == 0) { + this->Logic2Layer[targetedTile] = this->Logic2Layer[targetedTile] | L2_EARTH_AND_STONES; + this->BuildingWasLayer[targetedTile] = 0; + } + this->BuildingLayer[targetedTile] = 0; + buildingSizeTileIndex++; + this->ChangedLayer[targetedTile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 883e05366..c3ca092fa 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42159,7 +42159,7 @@ SHC_3BB0A8C1_0x00508540 | 0.0% | Pending SHC_3BB0A8C1_0x00508590 | 0.0% | Pending -SHC_3BB0A8C1_0x00508760 | 0.0% | Pending +SHC_3BB0A8C1_0x00508760 | 69.0% | ecx not kept across callee SHC_3BB0A8C1_0x00508870 | 88.9% | Style pass, asm differs From cb5ff5fb0e776b1b3fa63875f80760f76b9b9a32 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 07:26:32 +0200 Subject: [PATCH 100/252] reimplement: SHC_3BB0A8C1_0x004FAF70 98.51% offset walk regalloc --- .../clearStockpileFootprintTiles.cpp | 64 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearStockpileFootprintTiles.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearStockpileFootprintTiles.cpp b/src/OpenSHC/Map/TileMapState/clearStockpileFootprintTiles.cpp new file mode 100644 index 000000000..af75f0302 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearStockpileFootprintTiles.cpp @@ -0,0 +1,64 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAF70 + void TileMapState::clearStockpileFootprintTiles(int x, int y) + { + int tile; + for (int offset = 0; offset < 9; offset += 3) { + tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 0].y + y] + .addXgetTile + + x + DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 0].x; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + if (DAT_BuildingsState::instance.buildings[this->AlphaGFXLayer[tile]].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } + this->AlphaGFXLayer[tile] = 0; + tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 1].y + y] + .addXgetTile + + x + DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 1].x; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + if (DAT_BuildingsState::instance.buildings[this->AlphaGFXLayer[tile]].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } + this->AlphaGFXLayer[tile] = 0; + tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 2].y + y] + .addXgetTile + + x + DAT_TerrainDefinedData::instance.StockpilePathableOffsets[offset + 2].x; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + if (DAT_BuildingsState::instance.buildings[this->AlphaGFXLayer[tile]].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } + this->AlphaGFXLayer[tile] = 0; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c3ca092fa..9a32b01d1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40367,7 +40367,7 @@ SHC_3BB0A8C1_0x004FAE50 | 35.1% | ecx not kept across callee SHC_3BB0A8C1_0x004FAEE0 | 55.3% | ecx not kept across callee -SHC_3BB0A8C1_0x004FAF70 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAF70 | 98.5% | offset walk regalloc SHC_3BB0A8C1_0x004FB0C0 | 0.0% | Pending From ba149a424ed270bf2126ab8b8ecfa73bc93232bb Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 09:13:14 +0200 Subject: [PATCH 101/252] reimplement: SHC_3BB0A8C1_0x004FF870 74.67% __asm; global not nameable --- ...BitFlagBasedOnWallTowerGatehouseOrKeep.cpp | 122 ++++++++++++------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 87 insertions(+), 37 deletions(-) diff --git a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp index 21d6a0bf8..958076193 100644 --- a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp +++ b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp @@ -6,12 +6,6 @@ namespace OpenSHC { namespace Map { - using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; - using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; - - /* - WARNING: Restarted to delay deadcode elimination for space: ram - */ /* WARNING: Enum "MappersEnum": Some values do not have unique names */ @@ -21,42 +15,98 @@ namespace Map { // FUNCTION: STRONGHOLDCRUSADER 0x004FF870 byte TileMapState::setBitFlagBasedOnWallTowerGatehouseOrKeep(int x, int y) { + /* + The original is handwritten assembly: it materialises zero with "mov edx, 0" instead of + "xor edx, edx", advances the tile pointer with four "add esi, ecx" instead of a scaled lea, + and spills the row base with a bare push/pop across the middle of the body. Written as C++ + it would be: + + this->bitFlag = 0; + if ((this->ptr_LogicLayer[this->DAT_SomeTile + 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { + this->bitFlag = 0x20; + } + ... and so on for the eight neighbours, where the north row is offset by + ptr_MovementDirectionTranslationMatrix[DAT_SomeY * 8 + 0] and the south row by [+ 4]. + + Offsets used below (this is TileMapState): + 0x554a38 DAT_SomeY + 0x554a3c DAT_SomeTile + 0x554a40 bitFlag + 0x554a58 ptr_LogicLayer + 0x554a68 ptr_MovementDirectionTranslationMatrix + */ this->DAT_SomeY = y; this->DAT_SomeTile = MACRO_CALL_MEMBER( OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, DAT_ViewportRenderState::ptr)(x, y); - this->bitFlag = 0; - if ((((uint*)this->ptr_LogicLayer)[this->DAT_SomeTile + 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) - != 0) { - this->bitFlag = 0x20; - } - if ((((uint*)this->ptr_LogicLayer)[this->DAT_SomeTile - 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) - != 0) { - this->bitFlag = this->bitFlag | 2; - } - uint* northRow = (uint*)this->ptr_LogicLayer + this->DAT_SomeTile - + ((int*)this->ptr_MovementDirectionTranslationMatrix)[this->DAT_SomeY * 8]; - if ((northRow[-1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 1; - } - if ((northRow[1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 0x40; - } - if ((*northRow & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 0x80; + __asm { + mov eax, this + mov edi, dword ptr [eax + 0x554a68] + mov esi, dword ptr [eax + 0x554a58] + mov eax, dword ptr [eax + 0x554a3c] + shl eax, 0x2 + add esi, eax + push esi + mov eax, this + mov eax, dword ptr [eax + 0x554a38] + shl eax, 0x5 + add edi, eax + mov edx, 0x0 + mov eax, dword ptr [esi + 0x4] + mov ebx, dword ptr [esi - 0x4] + and eax, 0x10000100 + jz east_done + or edx, 0x20 + east_done: + and ebx, 0x10000100 + jz west_done + or edx, 0x2 + west_done: + mov ecx, dword ptr [edi] + add esi, ecx + add esi, ecx + add esi, ecx + add esi, ecx + mov eax, dword ptr [esi - 0x4] + mov ebx, dword ptr [esi + 0x4] + mov ecx, dword ptr [esi] + and eax, 0x10000100 + jz north_west_done + or edx, 0x1 + north_west_done: + and ebx, 0x10000100 + jz north_east_done + or edx, 0x40 + north_east_done: + and ecx, 0x10000100 + jz north_done + or edx, 0x80 + north_done: + mov ecx, dword ptr [edi + 0x10] + pop esi + add esi, ecx + add esi, ecx + add esi, ecx + add esi, ecx + mov eax, dword ptr [esi - 0x4] + mov ebx, dword ptr [esi + 0x4] + mov ecx, dword ptr [esi] + and eax, 0x10000100 + jz south_west_done + or edx, 0x4 + south_west_done: + and ebx, 0x10000100 + jz south_east_done + or edx, 0x10 + south_east_done: + and ecx, 0x10000100 + jz south_done + or edx, 0x8 + south_done: + mov eax, this + mov byte ptr [eax + 0x554a40], dl } - uint* southRow = (uint*)this->ptr_LogicLayer + this->DAT_SomeTile - + ((int*)this->ptr_MovementDirectionTranslationMatrix)[this->DAT_SomeY * 8 + 4]; - if ((southRow[-1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 4; - } - if ((southRow[1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 0x10; - } - if ((*southRow & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { - this->bitFlag = this->bitFlag | 8; - } return this->bitFlag; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9a32b01d1..79a7858d6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41103,7 +41103,7 @@ SHC_3BB0A8C1_0x004FF080 | 0.0% | Pending SHC_3BB0A8C1_0x004FF420 | 0.0% | Pending -SHC_3BB0A8C1_0x004FF870 | 8.9% | original built unoptimised +SHC_3BB0A8C1_0x004FF870 | 74.7% | __asm; global not nameable SHC_3BB0A8C1_0x004FF990 | 0.0% | Pending From 47ddf523f19ff8c54e4714c1fcfc29d47a4505e2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 09:24:44 +0200 Subject: [PATCH 102/252] reimplement: SHC_3BB0A8C1_0x004FF870 74.67% __asm; global not nameable --- ...BitFlagBasedOnWallTowerGatehouseOrKeep.cpp | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp index 958076193..1ab9ea3d8 100644 --- a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp +++ b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp @@ -18,8 +18,10 @@ namespace Map { /* The original is handwritten assembly: it materialises zero with "mov edx, 0" instead of "xor edx, edx", advances the tile pointer with four "add esi, ecx" instead of a scaled lea, - and spills the row base with a bare push/pop across the middle of the body. Written as C++ - it would be: + spills the row base with a bare push/pop across the middle of the body, and reaches the + fields through the global instance's absolute address rather than through this (which is why + the loads below differ: MSVC inline asm cannot name DAT_TileMapState::instance, as "::" is + not parseable there). Written as C++ it would be: this->bitFlag = 0; if ((this->ptr_LogicLayer[this->DAT_SomeTile + 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { @@ -27,13 +29,6 @@ namespace Map { } ... and so on for the eight neighbours, where the north row is offset by ptr_MovementDirectionTranslationMatrix[DAT_SomeY * 8 + 0] and the south row by [+ 4]. - - Offsets used below (this is TileMapState): - 0x554a38 DAT_SomeY - 0x554a3c DAT_SomeTile - 0x554a40 bitFlag - 0x554a58 ptr_LogicLayer - 0x554a68 ptr_MovementDirectionTranslationMatrix */ this->DAT_SomeY = y; this->DAT_SomeTile = MACRO_CALL_MEMBER( @@ -41,14 +36,14 @@ namespace Map { __asm { mov eax, this - mov edi, dword ptr [eax + 0x554a68] - mov esi, dword ptr [eax + 0x554a58] - mov eax, dword ptr [eax + 0x554a3c] + mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix + mov esi, dword ptr [eax]TileMapState.ptr_LogicLayer + mov eax, dword ptr [eax]TileMapState.DAT_SomeTile shl eax, 0x2 add esi, eax push esi mov eax, this - mov eax, dword ptr [eax + 0x554a38] + mov eax, dword ptr [eax]TileMapState.DAT_SomeY shl eax, 0x5 add edi, eax mov edx, 0x0 @@ -104,7 +99,7 @@ namespace Map { or edx, 0x8 south_done: mov eax, this - mov byte ptr [eax + 0x554a40], dl + mov byte ptr [eax]TileMapState.bitFlag, dl } return this->bitFlag; From b55b568de5351cc4ff608ca36cd2951e31a8faee Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 10:16:09 +0200 Subject: [PATCH 103/252] asm: shared macro for the handwritten neighbour-flag block The original gathers the neighbours of DAT_SomeTile into bitFlag with handwritten assembly, and that assembly is a macro rather than a function: the identical instruction stream appears verbatim inside setBitFlagBasedOnWallTowerGatehouseOrKeep (0x004FF870, once), updateGFXLayers (0x004FC9E0, 9x), updateMacroLayerRelated (0x004FDB00, 11x) and updateGfxLayer (0x00509180, 19x) - never as a call. Tells that it is handwritten: "mov edx, 0" where any compiler emits xor, a row pointer advanced by repeated "add esi, ecx" instead of one scaled lea, and, in the TERRAIN variants, a dword load at a one-byte offset masked down to the low byte. Four shapes occur, parameterised here as LOGIC/TERRAIN (which layer pointer, and so the element size) x _4/_8 (cardinal neighbours only, or all eight). ID keeps the asm labels of two expansions in the same function apart; MASK must be a literal or a preprocessor constant because MASM has no "|" operator. Verified against setBitFlagBasedOnWallTowerGatehouseOrKeep: the macro reproduces the hand-written asm byte for byte, 74.67% unchanged. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- .../Map/TileMapState/NeighbourFlagsAsm.hpp | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 src/OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp diff --git a/src/OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp b/src/OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp new file mode 100644 index 000000000..b0e32c6ee --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp @@ -0,0 +1,255 @@ +/** + HAND WRITTEN - not generated. + + path: 'OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp' + + The original gathers the neighbours of DAT_SomeTile into bitFlag with handwritten assembly, and that + assembly is a MACRO: the identical instruction stream appears verbatim inside + setBitFlagBasedOnWallTowerGatehouseOrKeep (0x004FF870, once), updateGFXLayers (0x004FC9E0, nine + times), updateMacroLayerRelated (0x004FDB00, eleven times) and updateGfxLayer (0x00509180, nineteen + times) - never as a call. It is recognisable by "mov edx, 0" (no compiler materialises zero that + way), by advancing the row pointer with repeated "add esi, ecx" instead of one scaled lea, and, in + the TERRAIN variants, by loading a dword at a one-byte offset and masking it down to the low byte. + + Four shapes occur, selected by which layer pointer is read and how many neighbours are gathered: + + LOGIC - ptr_LogicLayer, 4-byte elements: "shl eax, 2", "add esi, ecx" x4, [esi +/- 4] + TERRAIN - ptr_TerrainTypeTileMap, 1-byte elements: no shift, "add esi, ecx" x1, [esi +/- 1] + _4 - east, west, north and south only + _8 - also north-west, north-east, south-west and south-east + + bitFlag bits: 0x02 west, 0x20 east, 0x80 north, 0x08 south, + 0x01 north-west, 0x40 north-east, 0x04 south-west, 0x10 south-east. + + Every expansion clobbers eax, ebx, ecx, edx, esi and edi and leaves the result in this->bitFlag. + + ID must be unique within the enclosing function; it exists only to keep the asm labels of two + expansions apart. MASK must be a numeric literal or a preprocessor constant: MASM has no "|" + operator, so an enum OR expression cannot be used as an asm operand. + + The original reaches the fields through the global instance's absolute address; we go through "this" + because MSVC inline asm cannot name DAT_TileMapState::instance ("::" is not parseable in an asm + operand). That costs the "mov eax, this" instructions and nothing else. +*/ + +#pragma once + +#include "OpenSHC/Map/TileMapState.hpp" + +// clang-format off + +#define MACRO_NEIGHBOUR_FLAGS_LOGIC_4(ID, MASK) \ + __asm mov eax, this \ + __asm mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix \ + __asm mov esi, dword ptr [eax]TileMapState.ptr_LogicLayer \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeTile \ + __asm shl eax, 0x2 \ + __asm add esi, eax \ + __asm push esi \ + __asm mov eax, this \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeY \ + __asm shl eax, 0x5 \ + __asm add edi, eax \ + __asm mov edx, 0x0 \ + __asm mov eax, dword ptr [esi + 0x4] \ + __asm mov ebx, dword ptr [esi - 0x4] \ + __asm and eax, MASK \ + __asm jz east_done_##ID \ + __asm or edx, 0x20 \ + __asm east_done_##ID: \ + __asm and ebx, MASK \ + __asm jz west_done_##ID \ + __asm or edx, 0x2 \ + __asm west_done_##ID: \ + __asm mov ecx, dword ptr [edi] \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz north_done_##ID \ + __asm or edx, 0x80 \ + __asm north_done_##ID: \ + __asm mov ecx, dword ptr [edi + 0x10] \ + __asm pop esi \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz south_done_##ID \ + __asm or edx, 0x8 \ + __asm south_done_##ID: \ + __asm mov eax, this \ + __asm mov byte ptr [eax]TileMapState.bitFlag, dl + +#define MACRO_NEIGHBOUR_FLAGS_LOGIC_8(ID, MASK) \ + __asm mov eax, this \ + __asm mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix \ + __asm mov esi, dword ptr [eax]TileMapState.ptr_LogicLayer \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeTile \ + __asm shl eax, 0x2 \ + __asm add esi, eax \ + __asm push esi \ + __asm mov eax, this \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeY \ + __asm shl eax, 0x5 \ + __asm add edi, eax \ + __asm mov edx, 0x0 \ + __asm mov eax, dword ptr [esi + 0x4] \ + __asm mov ebx, dword ptr [esi - 0x4] \ + __asm and eax, MASK \ + __asm jz east_done_##ID \ + __asm or edx, 0x20 \ + __asm east_done_##ID: \ + __asm and ebx, MASK \ + __asm jz west_done_##ID \ + __asm or edx, 0x2 \ + __asm west_done_##ID: \ + __asm mov ecx, dword ptr [edi] \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi - 0x4] \ + __asm mov ebx, dword ptr [esi + 0x4] \ + __asm mov ecx, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz north_west_done_##ID \ + __asm or edx, 0x1 \ + __asm north_west_done_##ID: \ + __asm and ebx, MASK \ + __asm jz north_east_done_##ID \ + __asm or edx, 0x40 \ + __asm north_east_done_##ID: \ + __asm and ecx, MASK \ + __asm jz north_done_##ID \ + __asm or edx, 0x80 \ + __asm north_done_##ID: \ + __asm mov ecx, dword ptr [edi + 0x10] \ + __asm pop esi \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi - 0x4] \ + __asm mov ebx, dword ptr [esi + 0x4] \ + __asm mov ecx, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz south_west_done_##ID \ + __asm or edx, 0x4 \ + __asm south_west_done_##ID: \ + __asm and ebx, MASK \ + __asm jz south_east_done_##ID \ + __asm or edx, 0x10 \ + __asm south_east_done_##ID: \ + __asm and ecx, MASK \ + __asm jz south_done_##ID \ + __asm or edx, 0x8 \ + __asm south_done_##ID: \ + __asm mov eax, this \ + __asm mov byte ptr [eax]TileMapState.bitFlag, dl + +#define MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(ID, MASK) \ + __asm mov eax, this \ + __asm mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix \ + __asm mov esi, dword ptr [eax]TileMapState.ptr_TerrainTypeTileMap \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeTile \ + __asm add esi, eax \ + __asm push esi \ + __asm mov eax, this \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeY \ + __asm shl eax, 0x5 \ + __asm add edi, eax \ + __asm mov edx, 0x0 \ + __asm mov eax, dword ptr [esi + 0x1] \ + __asm mov ebx, dword ptr [esi - 0x1] \ + __asm and eax, MASK \ + __asm jz east_done_##ID \ + __asm or edx, 0x20 \ + __asm east_done_##ID: \ + __asm and ebx, MASK \ + __asm jz west_done_##ID \ + __asm or edx, 0x2 \ + __asm west_done_##ID: \ + __asm mov ecx, dword ptr [edi] \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz north_done_##ID \ + __asm or edx, 0x80 \ + __asm north_done_##ID: \ + __asm mov ecx, dword ptr [edi + 0x10] \ + __asm pop esi \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz south_done_##ID \ + __asm or edx, 0x8 \ + __asm south_done_##ID: \ + __asm mov eax, this \ + __asm mov byte ptr [eax]TileMapState.bitFlag, dl + +#define MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(ID, MASK) \ + __asm mov eax, this \ + __asm mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix \ + __asm mov esi, dword ptr [eax]TileMapState.ptr_TerrainTypeTileMap \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeTile \ + __asm add esi, eax \ + __asm push esi \ + __asm mov eax, this \ + __asm mov eax, dword ptr [eax]TileMapState.DAT_SomeY \ + __asm shl eax, 0x5 \ + __asm add edi, eax \ + __asm mov edx, 0x0 \ + __asm mov eax, dword ptr [esi + 0x1] \ + __asm mov ebx, dword ptr [esi - 0x1] \ + __asm and eax, MASK \ + __asm jz east_done_##ID \ + __asm or edx, 0x20 \ + __asm east_done_##ID: \ + __asm and ebx, MASK \ + __asm jz west_done_##ID \ + __asm or edx, 0x2 \ + __asm west_done_##ID: \ + __asm mov ecx, dword ptr [edi] \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi - 0x1] \ + __asm mov ebx, dword ptr [esi + 0x1] \ + __asm mov ecx, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz north_west_done_##ID \ + __asm or edx, 0x1 \ + __asm north_west_done_##ID: \ + __asm and ebx, MASK \ + __asm jz north_east_done_##ID \ + __asm or edx, 0x40 \ + __asm north_east_done_##ID: \ + __asm and ecx, MASK \ + __asm jz north_done_##ID \ + __asm or edx, 0x80 \ + __asm north_done_##ID: \ + __asm mov ecx, dword ptr [edi + 0x10] \ + __asm pop esi \ + __asm add esi, ecx \ + __asm mov eax, dword ptr [esi - 0x1] \ + __asm mov ebx, dword ptr [esi + 0x1] \ + __asm mov ecx, dword ptr [esi] \ + __asm and eax, MASK \ + __asm jz south_west_done_##ID \ + __asm or edx, 0x4 \ + __asm south_west_done_##ID: \ + __asm and ebx, MASK \ + __asm jz south_east_done_##ID \ + __asm or edx, 0x10 \ + __asm south_east_done_##ID: \ + __asm and ecx, MASK \ + __asm jz south_done_##ID \ + __asm or edx, 0x8 \ + __asm south_done_##ID: \ + __asm mov eax, this \ + __asm mov byte ptr [eax]TileMapState.bitFlag, dl + +// clang-format on From 26f19066e007e03438fc4a4e9512eec58a5f64ca Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 10:16:18 +0200 Subject: [PATCH 104/252] reimplement: SHC_3BB0A8C1_0x004FF870 74.67% Style pass, asm differs --- ...BitFlagBasedOnWallTowerGatehouseOrKeep.cpp | 79 ++----------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 7 insertions(+), 74 deletions(-) diff --git a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp index 1ab9ea3d8..7103bd749 100644 --- a/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp +++ b/src/OpenSHC/Map/TileMapState/setBitFlagBasedOnWallTowerGatehouseOrKeep.cpp @@ -1,8 +1,11 @@ #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#define NEIGHBOUR_FLAGS_MASK_WALL_OR_KEEP 0x10000100 // L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE + namespace OpenSHC { namespace Map { @@ -16,12 +19,8 @@ namespace Map { byte TileMapState::setBitFlagBasedOnWallTowerGatehouseOrKeep(int x, int y) { /* - The original is handwritten assembly: it materialises zero with "mov edx, 0" instead of - "xor edx, edx", advances the tile pointer with four "add esi, ecx" instead of a scaled lea, - spills the row base with a bare push/pop across the middle of the body, and reaches the - fields through the global instance's absolute address rather than through this (which is why - the loads below differ: MSVC inline asm cannot name DAT_TileMapState::instance, as "::" is - not parseable there). Written as C++ it would be: + The body is the handwritten neighbour-flag macro; see NeighbourFlagsAsm.hpp. Written as C++ + it would be: this->bitFlag = 0; if ((this->ptr_LogicLayer[this->DAT_SomeTile + 1] & (L_WALL_OR_GATEHOUSE | L_KEEP_NON_MANOR_HOUSE)) != 0) { @@ -34,73 +33,7 @@ namespace Map { this->DAT_SomeTile = MACRO_CALL_MEMBER( OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, DAT_ViewportRenderState::ptr)(x, y); - __asm { - mov eax, this - mov edi, dword ptr [eax]TileMapState.ptr_MovementDirectionTranslationMatrix - mov esi, dword ptr [eax]TileMapState.ptr_LogicLayer - mov eax, dword ptr [eax]TileMapState.DAT_SomeTile - shl eax, 0x2 - add esi, eax - push esi - mov eax, this - mov eax, dword ptr [eax]TileMapState.DAT_SomeY - shl eax, 0x5 - add edi, eax - mov edx, 0x0 - mov eax, dword ptr [esi + 0x4] - mov ebx, dword ptr [esi - 0x4] - and eax, 0x10000100 - jz east_done - or edx, 0x20 - east_done: - and ebx, 0x10000100 - jz west_done - or edx, 0x2 - west_done: - mov ecx, dword ptr [edi] - add esi, ecx - add esi, ecx - add esi, ecx - add esi, ecx - mov eax, dword ptr [esi - 0x4] - mov ebx, dword ptr [esi + 0x4] - mov ecx, dword ptr [esi] - and eax, 0x10000100 - jz north_west_done - or edx, 0x1 - north_west_done: - and ebx, 0x10000100 - jz north_east_done - or edx, 0x40 - north_east_done: - and ecx, 0x10000100 - jz north_done - or edx, 0x80 - north_done: - mov ecx, dword ptr [edi + 0x10] - pop esi - add esi, ecx - add esi, ecx - add esi, ecx - add esi, ecx - mov eax, dword ptr [esi - 0x4] - mov ebx, dword ptr [esi + 0x4] - mov ecx, dword ptr [esi] - and eax, 0x10000100 - jz south_west_done - or edx, 0x4 - south_west_done: - and ebx, 0x10000100 - jz south_east_done - or edx, 0x10 - south_east_done: - and ecx, 0x10000100 - jz south_done - or edx, 0x8 - south_done: - mov eax, this - mov byte ptr [eax]TileMapState.bitFlag, dl - } + MACRO_NEIGHBOUR_FLAGS_LOGIC_8(1, NEIGHBOUR_FLAGS_MASK_WALL_OR_KEEP) return this->bitFlag; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 79a7858d6..5faaca055 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41103,7 +41103,7 @@ SHC_3BB0A8C1_0x004FF080 | 0.0% | Pending SHC_3BB0A8C1_0x004FF420 | 0.0% | Pending -SHC_3BB0A8C1_0x004FF870 | 74.7% | __asm; global not nameable +SHC_3BB0A8C1_0x004FF870 | 74.7% | __asm macro; global not nameable SHC_3BB0A8C1_0x004FF990 | 0.0% | Pending From 519cace11b069aee1aa229ded278586870fd6a55 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 10:42:51 +0200 Subject: [PATCH 105/252] reimplement: SHC_3BB0A8C1_0x004FC9E0 64.51% Od stack slot order differs --- .../Map/TileMapState/updateGFXLayers.cpp | 358 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp b/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp new file mode 100644 index 000000000..9b9890f70 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp @@ -0,0 +1,358 @@ +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +// masks for the handwritten neighbour-flag macro; MASM has no "|", so these must be literals +#define NEIGHBOUR_FLAGS_MASK_MARSH 0x20000000 // L_MARSH +#define NEIGHBOUR_FLAGS_MASK_SEA 0x1 // L_SEA +#define NEIGHBOUR_FLAGS_MASK_DEFAULT_EARTH 0x8000 // L_DEFAULT_EARTH_OR_TEXTURE +#define NEIGHBOUR_FLAGS_MASK_L2_SCRUB 0x1 // L2_SCRUB +#define NEIGHBOUR_FLAGS_MASK_L2_EARTH_AND_STONES 0x2 // L2_EARTH_AND_STONES +#define NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_MEDIUM 0x4 // L2_PLATEAU_MEDIUM +#define NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_HIGH 0x8 // L2_PLATEAU_HIGH +#define NEIGHBOUR_FLAGS_MASK_L2_OASIS_GRASS 0x10 // L2_OASIS_GRASS +#define NEIGHBOUR_FLAGS_MASK_L2_BEACH 0x20 // L2_BEACH +#define NEIGHBOUR_FLAGS_MASK_L2_STONES 0x40 // L2_STONES_OR_DRIVEN_SANDUnk + +#pragma optimize("", off) + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_BEACH; + using OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_MEDIUM; + using OpenSHC::Map::LogicHelpers::L2_SCRUB; + using OpenSHC::Map::LogicHelpers::L2_STONES_OR_DRIVEN_SANDUnk; + using OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + using OpenSHC::Map::LogicHelpers::L_DEFAULT_EARTH_OR_TEXTURE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC9E0 + void TileMapState::updateGFXLayers() + { + /* + Contains the handwritten neighbour-flag macro nine times (see NeighbourFlagsAsm.hpp), which + is why the surrounding code is unoptimised: MSVC disables optimisation in a function holding + inline asm, so every field access reloads this from the frame. + + Two stores below are dead in this function but present in the original, because the body is + shared with updateMacroLayerRelated where they are read: "rotation" is reassigned from + MacroLayer at the end of the tile setup, and "height" is never read at all. + */ + /* + The locals are declared here, in this order, because the original was built without + optimisation: its stack slots are observable and MSVC assigns them per function, not per + scope. Declaring them at first use instead costs ~12 points of match (52.6% vs 64.5%). + */ + int rotation; + int blockColumn; + int gfxMode; + int index; + int macroHigh; + int blockRow; + int gfxBaseD; + int luminescence; + int gfxStride; + int subRow; + int subColumn; + int gfxBaseA; + int macroLow; + int gfxBaseE; + int height; + int gfxBaseB; + int gfxBaseC; + int macroMid; + int savedBitFlag; + + if ((int)this->forceUpdateGFXLayers <= 0) { + return; + } + this->forceUpdateGFXLayers = this->forceUpdateGFXLayers - 1; + + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::getYSmallerThanYLimit, DAT_PathFindingState::ptr)() + == FALSE) { + return; + } + + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; (int)blockRow <= (int)this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; (int)blockColumn <= (int)this->someYLikeLimit; blockColumn++) { + if ((char)this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if ((this->LogicLayer[this->DAT_SomeTile] & L_DEFAULT_EARTH_OR_TEXTURE) != 0) { + if (this->GfxLayer[this->DAT_SomeTile] == 0) { + luminescence = this->LuminesenceLayer[this->DAT_SomeTile]; + if (luminescence < 2) { + luminescence = 2; + } + macroLow = this->MacroLayer[this->DAT_SomeTile] & 0x3f; + macroMid = (this->MacroLayer[this->DAT_SomeTile] & 0x7c0) >> 6; + macroHigh = (this->MacroLayer[this->DAT_SomeTile] & 0xf000) >> 12; + macroHigh = macroHigh & 3; + rotation = this->MacroLayer[this->DAT_SomeTile]; + this->PillarGFXLayer[this->DAT_SomeTile] + = (ushort)GMTotalPicturesProcessed::instance[9]; + + if ((this->LogicLayer[this->DAT_SomeTile] & L_MARSH) != 0) { + MACRO_NEIGHBOUR_FLAGS_LOGIC_4(1, NEIGHBOUR_FLAGS_MASK_MARSH) + gfxBaseA = 1; + gfxBaseB = 3; + gfxBaseC = 0x15; + gfxBaseD = 0x21; + gfxBaseE = 0x25; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_EARTH_AND_STONES) != 0) { + height = this->HeightLayer[this->DAT_SomeTile]; + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(2, NEIGHBOUR_FLAGS_MASK_L2_EARTH_AND_STONES) + gfxBaseA = 0x99; + gfxBaseB = 0x9b; + gfxBaseC = 0xad; + gfxBaseD = 0xb9; + gfxBaseE = 0xbd; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_OASIS_GRASS) != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(3, NEIGHBOUR_FLAGS_MASK_L2_OASIS_GRASS) + gfxBaseA = 0x1c9; + gfxBaseB = 0x1cb; + gfxBaseC = 0x1dd; + gfxBaseD = 0x1e9; + gfxBaseE = 0x1ed; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_STONES_OR_DRIVEN_SANDUnk) + != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(4, NEIGHBOUR_FLAGS_MASK_L2_STONES) + gfxBaseA = 0x261; + gfxBaseB = 0x263; + gfxBaseC = 0x275; + gfxBaseD = 0x281; + gfxBaseE = 0x285; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_SCRUB) != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(5, NEIGHBOUR_FLAGS_MASK_L2_SCRUB) + gfxBaseA = 0x2f9; + gfxBaseB = 0x2fb; + gfxBaseC = 0x30d; + gfxBaseD = 0x319; + gfxBaseE = 0x31d; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_THICK_SCRUB) != 0) { + /* the original gathers L2_SCRUB here, not L2_THICK_SCRUB; kept as-is */ + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(6, NEIGHBOUR_FLAGS_MASK_L2_SCRUB) + gfxBaseA = 0x4a9; + gfxBaseB = 0x4ab; + gfxBaseC = 0x4bd; + gfxBaseD = 0x4c9; + gfxBaseE = 0x4cd; + gfxStride = 4; + gfxMode = 0; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_PLATEAU_MEDIUM) != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(7, NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_MEDIUM) + gfxBaseA = 0x131; + gfxBaseB = 0x133; + gfxBaseC = 0x145; + gfxBaseD = 0x151; + gfxBaseE = 0x155; + gfxStride = 4; + gfxMode = 2; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_PLATEAU_HIGH) != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(8, NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_HIGH) + gfxBaseA = 0x131; + gfxBaseB = 0x133; + gfxBaseC = 0x145; + gfxBaseD = 0x151; + gfxBaseE = 0x155; + gfxStride = 4; + gfxMode = 2; + } else if ((this->Logic2Layer[this->DAT_SomeTile] & L2_BEACH) != 0) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_4(9, NEIGHBOUR_FLAGS_MASK_L2_BEACH) + savedBitFlag = this->bitFlag; + MACRO_NEIGHBOUR_FLAGS_LOGIC_4(10, NEIGHBOUR_FLAGS_MASK_SEA) + this->bitFlag = this->bitFlag | savedBitFlag; + gfxBaseA = 0x391; + gfxBaseB = 0x393; + gfxBaseC = 0x3a5; + gfxBaseD = 0x3b1; + gfxBaseE = 0x3b5; + gfxStride = 4; + gfxMode = 0; + } else { + MACRO_NEIGHBOUR_FLAGS_LOGIC_4(11, NEIGHBOUR_FLAGS_MASK_DEFAULT_EARTH) + gfxBaseA = 0x131; + gfxBaseB = 0x133; + gfxBaseC = 0x145; + gfxBaseD = 0x151; + gfxBaseE = 0x155; + gfxStride = 4; + gfxMode = 2; + } + + if (macroLow == 1) { + this->bitFlag = ~this->bitFlag; + this->bitFlag = this->bitFlag & 0xaa; + if (this->mapOrientation == 0) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 0); + } else if (this->mapOrientation == 2) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 2); + } else if (this->mapOrientation == 4) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 4); + } else if (this->mapOrientation == 6) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 6); + } + + if (gfxMode == 1) { + this->GfxLayer[this->DAT_SomeTile] = 0; + for (index = 0; index < 4; index++) { + if (DAT_TerrainDefinedData::instance.field2296_0x1d54[index][0] + == this->bitFlag) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseA + + (luminescence - 2) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 1) + + DAT_TerrainDefinedData::instance + .field2296_0x1d54[index][1]; + } + } + for (index = 4; index < 8; index++) { + if (DAT_TerrainDefinedData::instance.field2296_0x1d54[index][0] + == this->bitFlag) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseB + + (luminescence - 2) * gfxStride - 1 + + DAT_TerrainDefinedData::instance + .field2296_0x1d54[index][1]; + } + } + if (this->GfxLayer[this->DAT_SomeTile] == 0) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseC + + (luminescence - 2) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } + } else if (luminescence == 2) { + if (this->bitFlag != 0) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseC + + (this->RandomLayer[this->DAT_SomeTile] & 7) - 1; + } else { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseD + + (this->RandomLayer[this->DAT_SomeTile] & 7) - 1; + } + } else if (gfxMode == 2) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseA + + (luminescence - 3) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else if (this->bitFlag != 0) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseA + + (luminescence - 3) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 1); + } else { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseB + + (luminescence - 3) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 1); + } + } else if (luminescence > 2) { + if (gfxMode == 0) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseB + + (luminescence - 3) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 1); + } else if (gfxMode == 2) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseA + + (luminescence - 3) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseD + + (luminescence - 2) * gfxStride - 1 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } + } else if (macroLow == 2) { + if (gfxMode == 0) { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseD + + (this->RandomLayer[this->DAT_SomeTile] & 7) - 1; + } else { + this->GfxLayer[this->DAT_SomeTile] + = GMTotalPicturesProcessed::instance[55] + gfxBaseD + + (this->RandomLayer[this->DAT_SomeTile] & 3) - 1; + } + } else if (macroLow == 4) { + macroMid = DAT_TerrainDefinedData::instance + .field2293_0x1a54[this->mapOrientation / 2][macroMid]; + this->GfxLayer[this->DAT_SomeTile] = GMTotalPicturesProcessed::instance[55] + + gfxBaseE + macroMid + macroHigh * 4 - 1; + } else if (macroLow == 8) { + macroMid = DAT_TerrainDefinedData::instance + .field2294_0x1b54[this->mapOrientation / 2][macroMid]; + this->GfxLayer[this->DAT_SomeTile] = macroHigh * 9 + + (GMTotalPicturesProcessed::instance[55] + gfxBaseE + macroMid) + 0xf; + } else if (macroLow == 0x10) { + macroMid = DAT_TerrainDefinedData::instance + .field2295_0x1c54[this->mapOrientation / 2][macroMid]; + this->GfxLayer[this->DAT_SomeTile] = macroHigh * 16 + + (GMTotalPicturesProcessed::instance[55] + gfxBaseE + macroMid) + 0x33; + } + } + } + } + } + } + } + } + } + } +} +} + +#pragma optimize("", on) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5faaca055..f360d95e5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41095,7 +41095,7 @@ SHC_3BB0A8C1_0x004FC7C0 | 79.0% | setg vs sbb/neg SHC_3BB0A8C1_0x004FC810 | 0.0% | Pending -SHC_3BB0A8C1_0x004FC9E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC9E0 | 64.5% | Od stack slot order differs SHC_3BB0A8C1_0x004FDB00 | 0.0% | Pending From c526ee66cd933eef7a714076744626abd8a89cb3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 10:55:25 +0200 Subject: [PATCH 106/252] types: signed TileMapState fields, and mapping40x40 holds char Ten fields the reimplementations had to cast at every use. The original compares each of them with a signed branch (jg/jle/jl), so they are int rather than undefined4: someIndex, someLimit, someYLike, someYLikeLimit (0x004FC9E0 updateGFXLayers) forceUpdateGFXLayers (0x004FC9E0) forceUpdateMacroLayerFlag (0x00511020 updateMacroLayer) maxPitchDitchCount (0x00500850 getPitchDitchIDForTile) buildingMinHeight, buildingMaxHeight (0x004F9980 storeMinAndMaxHeightOfArea) mapping40x40 is read with movsx (0x004FC9E0, 0x004FDB00), so its element type is char, not byte. All four affected sources keep their match exactly (100.00%, 34.23%, 64.51%, 81.82%); the change only removes the casts. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TileMapState.hpp | 20 +++++++++---------- .../TileMapState/getPitchDitchIDForTile.cpp | 2 +- .../storeMinAndMaxHeightOfArea.cpp | 4 ++-- .../Map/TileMapState/updateGFXLayers.cpp | 8 ++++---- .../Map/TileMapState/updateMacroLayer.cpp | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/OpenSHC/Map/TileMapState.hpp b/src/OpenSHC/Map/TileMapState.hpp index 4eeb5af15..578e21a69 100644 --- a/src/OpenSHC/Map/TileMapState.hpp +++ b/src/OpenSHC/Map/TileMapState.hpp @@ -78,11 +78,11 @@ namespace Map { uchar unitDeathHeatMap[80400]; // 0x00428370 length: 80400 uchar SEC_TileMap1104[80400]; // 0x0043BD80 length: 80400 uchar SEC_PathfindingCostTileMap1105[9][80400]; // 0x0044F790 length: 723600 - undefined4 someIndex; // 0x00500220 length: 4 - undefined4 someLimit; // 0x00500224 length: 4 - undefined4 someYLike; // 0x00500228 length: 4 - undefined4 someYLikeLimit; // 0x0050022C length: 4 - byte mapping40x40[40][40]; // 0x00500230 length: 1600 + int someIndex; // 0x00500220 length: 4 + int someLimit; // 0x00500224 length: 4 + int someYLike; // 0x00500228 length: 4 + int someYLikeLimit; // 0x0050022C length: 4 + char mapping40x40[40][40]; // 0x00500230 length: 1600 Moat moats[16000]; // 0x00500870 length: 256000 int currentMoatCount; // 0x0053F070 length: 4 undefined4 moatTileCount; // 0x0053F074 length: 4 @@ -90,7 +90,7 @@ namespace Map { undefined4 ALG_MoatYResult; // 0x0053F07C length: 4 int someMoatTile; // 0x0053F080 length: 4 PitchDitch pitchDitches[4000]; // 0x0053F084 length: 80000 - undefined4 maxPitchDitchCount; // 0x00552904 length: 4 + int maxPitchDitchCount; // 0x00552904 length: 4 undefined1 padding_0x552908[4]; // 0x00552908 length: 4 short specialAreasArray[8]; // 0x0055290C length: 16 undefined4 temporaryTerrainTypeIndex; // 0x0055291C length: 4 @@ -101,8 +101,8 @@ namespace Map { int temporaryTerrainTypeBinaryArray[1000]; // 0x005538CC length: 4000 undefined4 forceUpdateLogicalAndMiscDisplayLayers; // 0x0055486C length: 4 undefined4 forceUpdateTextureTilemap; // 0x00554870 length: 4 - undefined4 forceUpdateGFXLayers; // 0x00554874 length: 4 - undefined4 forceUpdateMacroLayerFlag; // 0x00554878 length: 4 + int forceUpdateGFXLayers; // 0x00554874 length: 4 + int forceUpdateMacroLayerFlag; // 0x00554878 length: 4 undefined4 field68_0x55487c; // 0x0055487C length: 4 undefined1 padding_0x554880[8]; // 0x00554880 length: 8 undefined4 placedBuildingID; // 0x00554888 length: 4 @@ -158,8 +158,8 @@ namespace Map { undefined4 buildingSpriteID2; // 0x00554950 length: 4 undefined4 field131_0x554954; // 0x00554954 length: 4 undefined4 buildingHeightLimit; // 0x00554958 length: 4 - undefined4 buildingMinHeight; // 0x0055495C length: 4 - undefined4 buildingMaxHeight; // 0x00554960 length: 4 + int buildingMinHeight; // 0x0055495C length: 4 + int buildingMaxHeight; // 0x00554960 length: 4 undefined4 buildingMaxHeightDifference; // 0x00554964 length: 4 undefined4 buildingPlacementProperty_3; // 0x00554968 length: 4 undefined4 buildingPlacementProperty_4; // 0x0055496C length: 4 diff --git a/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp b/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp index efa5983db..e58957b63 100644 --- a/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp +++ b/src/OpenSHC/Map/TileMapState/getPitchDitchIDForTile.cpp @@ -12,7 +12,7 @@ namespace Map { // FUNCTION: STRONGHOLDCRUSADER 0x00500850 int TileMapState::getPitchDitchIDForTile(int tile) { - for (int pitchDitchID = 1; pitchDitchID < (int)this->maxPitchDitchCount; pitchDitchID++) { + for (int pitchDitchID = 1; pitchDitchID < this->maxPitchDitchCount; pitchDitchID++) { if (this->pitchDitches[pitchDitchID].owner != 0 && tile == this->pitchDitches[pitchDitchID].tile) { return pitchDitchID; } diff --git a/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp b/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp index 448f643c5..7022c8c67 100644 --- a/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp +++ b/src/OpenSHC/Map/TileMapState/storeMinAndMaxHeightOfArea.cpp @@ -35,10 +35,10 @@ namespace Map { uint height = this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[footprintY].addXgetTile + this->buildingX + x]; - if ((int)height > (int)this->buildingMaxHeight) { + if ((int)height > this->buildingMaxHeight) { this->buildingMaxHeight = height; } - if ((int)height < (int)this->buildingMinHeight) { + if ((int)height < this->buildingMinHeight) { this->buildingMinHeight = height; } } diff --git a/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp b/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp index 9b9890f70..127a2bcb2 100644 --- a/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp +++ b/src/OpenSHC/Map/TileMapState/updateGFXLayers.cpp @@ -81,7 +81,7 @@ namespace Map { int macroMid; int savedBitFlag; - if ((int)this->forceUpdateGFXLayers <= 0) { + if (this->forceUpdateGFXLayers <= 0) { return; } this->forceUpdateGFXLayers = this->forceUpdateGFXLayers - 1; @@ -93,9 +93,9 @@ namespace Map { } rotation = DAT_PathFindingState::instance.mappingYRelated % 10; - for (blockRow = this->someIndex; (int)blockRow <= (int)this->someLimit; blockRow++) { - for (blockColumn = this->someYLike; (int)blockColumn <= (int)this->someYLikeLimit; blockColumn++) { - if ((char)this->mapping40x40[blockRow][blockColumn] != 0) { + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { subRow = rotation; rotation = 0; for (; subRow < 10; subRow++) { diff --git a/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp b/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp index 04276859e..da8a73e08 100644 --- a/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp +++ b/src/OpenSHC/Map/TileMapState/updateMacroLayer.cpp @@ -23,7 +23,7 @@ namespace Map { // FUNCTION: STRONGHOLDCRUSADER 0x00511020 void TileMapState::updateMacroLayer() { - if ((int)this->forceUpdateMacroLayerFlag <= 0) { + if (this->forceUpdateMacroLayerFlag <= 0) { return; } From ea3c60586c4fb749e06ee6713dd69a63e3c305da Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:01:27 +0200 Subject: [PATCH 107/252] reimplement: SHC_3BB0A8C1_0x004FDB00 56.32% Od stack slot order differs --- .../TileMapState/updateMacroLayerRelated.cpp | 339 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateMacroLayerRelated.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated.cpp b/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated.cpp new file mode 100644 index 000000000..0dbb19812 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated.cpp @@ -0,0 +1,339 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +// masks for the handwritten neighbour-flag macro; MASM has no "|", so these must be literals +#define NEIGHBOUR_FLAGS_MASK_DEFAULT_EARTH 0x8000 // L_DEFAULT_EARTH_OR_TEXTURE +#define NEIGHBOUR_FLAGS_MASK_MARSH 0x20000000 // L_MARSH +#define NEIGHBOUR_FLAGS_MASK_SEA 0x1 // L_SEA +#define NEIGHBOUR_FLAGS_MASK_L2_SCRUB 0x1 // L2_SCRUB +#define NEIGHBOUR_FLAGS_MASK_L2_EARTH_AND_STONES 0x2 // L2_EARTH_AND_STONES +#define NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_MEDIUM 0x4 // L2_PLATEAU_MEDIUM +#define NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_HIGH 0x8 // L2_PLATEAU_HIGH +#define NEIGHBOUR_FLAGS_MASK_L2_OASIS_GRASS 0x10 // L2_OASIS_GRASS +#define NEIGHBOUR_FLAGS_MASK_L2_BEACH 0x20 // L2_BEACH +#define NEIGHBOUR_FLAGS_MASK_L2_STONES 0x40 // L2_STONES_OR_DRIVEN_SANDUnk +#define NEIGHBOUR_FLAGS_MASK_L2_THICK_SCRUB 0x80 // L2_THICK_SCRUB + +#pragma optimize("", off) + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_OIL; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FDB00 + void TileMapState::updateMacroLayerRelated(uint logic1, uint logic2, int clearMacroFirst) + { + /* + Five copies of the same block/sub-tile loop skeleton, and eleven expansions of the + handwritten neighbour-flag macro (see NeighbourFlagsAsm.hpp). The original was built + without optimisation, so the pragma above is needed to reproduce its frame-pointer, + reload-per-access code shape; the locals are declared together, in this order, because + at /Od the stack slots are observable and MSVC assigns them per function, not per scope. + */ + int previousMacro; + int rotation; + int blockColumn; + int index; + int blockRow; + int neighbourTile; + int subRow; + int subColumn; + int tableY; + int randomValue; + int tableX; + int tileXOffset; + int savedBitFlag; + + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if (this->ChangedLayer[this->DAT_SomeTile] != 0) { + previousMacro = this->MacroLayer[this->DAT_SomeTile]; + if (clearMacroFirst != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0; + } + if ((this->LogicLayer[this->DAT_SomeTile] & logic1) != 0 + || (this->Logic2Layer[this->DAT_SomeTile] & logic2) != 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->bitFlag = 0; + } else if (logic1 == 0x8000) { + MACRO_NEIGHBOUR_FLAGS_LOGIC_8(1, NEIGHBOUR_FLAGS_MASK_DEFAULT_EARTH) + } else if (logic1 == 0x20000000) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_OIL) == 0) { + MACRO_NEIGHBOUR_FLAGS_LOGIC_8(2, NEIGHBOUR_FLAGS_MASK_MARSH) + if (this->bitFlag != 0xff) { + this->MacroLayer[this->DAT_SomeTile] = 1; + } else if ((this->RandomLayer[this->DAT_SomeTile] & 0xf) == 0) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } else { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + if (previousMacro != this->MacroLayer[this->DAT_SomeTile]) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(1, this->DAT_SomeX, this->DAT_SomeY); + } + } + } else if (logic2 == 0x2) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(3, NEIGHBOUR_FLAGS_MASK_L2_EARTH_AND_STONES) + } else if (logic2 == 0x10) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(4, NEIGHBOUR_FLAGS_MASK_L2_OASIS_GRASS) + } else if (logic2 == 0x1) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(5, NEIGHBOUR_FLAGS_MASK_L2_SCRUB) + } else if (logic2 == 0x80) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(6, NEIGHBOUR_FLAGS_MASK_L2_THICK_SCRUB) + } else if (logic2 == 0x40) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(7, NEIGHBOUR_FLAGS_MASK_L2_STONES) + } else if (logic2 == 0x20) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(8, NEIGHBOUR_FLAGS_MASK_L2_BEACH) + savedBitFlag = this->bitFlag; + MACRO_NEIGHBOUR_FLAGS_LOGIC_8(9, NEIGHBOUR_FLAGS_MASK_SEA) + this->bitFlag = this->bitFlag | savedBitFlag; + } else if (logic2 == 0x4) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(10, NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_MEDIUM) + } else if (logic2 == 0x8) { + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(11, NEIGHBOUR_FLAGS_MASK_L2_PLATEAU_HIGH) + } else { + this->bitFlag = 0; + } + if (this->bitFlag != 0xff) { + this->MacroLayer[this->DAT_SomeTile] = 1; + } else if ((this->RandomLayer[this->DAT_SomeTile] & 0xf) == 0) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } else { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + if (previousMacro != this->MacroLayer[this->DAT_SomeTile]) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(1, this->DAT_SomeX, this->DAT_SomeY); + } + } + } + } + } + } + } + } + } + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + tileXOffset = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::computeTileXOffset, + DAT_ViewportRenderState::ptr)(this->DAT_SomeTile, this->DAT_SomeY); + randomValue = this->RandomLayer[this->DAT_SomeTile] & 0xf; + for (index = 0; index < 0x10; index++) { + tableX = DAT_TerrainDefinedData::instance.field2292_0x19d4[index].x; + tableY = DAT_TerrainDefinedData::instance.field2292_0x19d4[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + if (this->MacroLayer[neighbourTile] != 0x800) { + break; + } + } + if (index >= 0x10) { + for (index = 0; index < 0x10; index++) { + tableX = DAT_TerrainDefinedData::instance.field2292_0x19d4[index].x; + tableY = DAT_TerrainDefinedData::instance.field2292_0x19d4[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + this->MacroLayer[neighbourTile] = 0x10; + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + (short)(index << 6); + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + randomValue * 0x1000; + } + } + } + } + } + } + } + } + } + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + tileXOffset = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::computeTileXOffset, + DAT_ViewportRenderState::ptr)(this->DAT_SomeTile, this->DAT_SomeY); + randomValue = this->RandomLayer[this->DAT_SomeTile] & 0xf; + for (index = 0; index < 9; index++) { + tableX = DAT_TerrainDefinedData::instance.field2291_0x198c[index].x; + tableY = DAT_TerrainDefinedData::instance.field2291_0x198c[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + if (this->MacroLayer[neighbourTile] != 0x800) { + break; + } + } + if (index >= 9) { + for (index = 0; index < 9; index++) { + tableX = DAT_TerrainDefinedData::instance.field2291_0x198c[index].x; + tableY = DAT_TerrainDefinedData::instance.field2291_0x198c[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + this->MacroLayer[neighbourTile] = 8; + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + (short)(index << 6); + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + randomValue * 0x1000; + } + } + } + } + } + } + } + } + } + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + tileXOffset = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::computeTileXOffset, + DAT_ViewportRenderState::ptr)(this->DAT_SomeTile, this->DAT_SomeY); + randomValue = this->RandomLayer[this->DAT_SomeTile] & 0xf; + for (index = 0; index < 4; index++) { + tableX = DAT_TerrainDefinedData::instance.field2290_0x196c[index].x; + tableY = DAT_TerrainDefinedData::instance.field2290_0x196c[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + if (this->MacroLayer[neighbourTile] != 0x800) { + break; + } + } + if (index >= 4) { + for (index = 0; index < 4; index++) { + tableX = DAT_TerrainDefinedData::instance.field2290_0x196c[index].x; + tableY = DAT_TerrainDefinedData::instance.field2290_0x196c[index].y; + neighbourTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)( + tileXOffset + tableX, this->DAT_SomeY + tableY); + this->MacroLayer[neighbourTile] = 4; + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + (short)(index << 6); + this->MacroLayer[neighbourTile] + = this->MacroLayer[neighbourTile] + randomValue * 0x1000; + } + } + } + } + } + } + } + } + } + rotation = DAT_PathFindingState::instance.mappingYRelated % 10; + for (blockRow = this->someIndex; blockRow <= this->someLimit; blockRow++) { + for (blockColumn = this->someYLike; blockColumn <= this->someYLikeLimit; blockColumn++) { + if (this->mapping40x40[blockRow][blockColumn] != 0) { + subRow = rotation; + rotation = 0; + for (; subRow < 10; subRow++) { + this->DAT_SomeY = blockRow * 10 + subRow; + this->DAT_SomeX = blockColumn * 10; + for (subColumn = 0; subColumn < 10; subColumn++, this->DAT_SomeX++) { + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY) + != FALSE) { + this->DAT_SomeTile + = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY); + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + } + } + } + } + } + } + +} +} + +#pragma optimize("", on) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f360d95e5..75bb113f2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41097,7 +41097,7 @@ SHC_3BB0A8C1_0x004FC810 | 0.0% | Pending SHC_3BB0A8C1_0x004FC9E0 | 64.5% | Od stack slot order differs -SHC_3BB0A8C1_0x004FDB00 | 0.0% | Pending +SHC_3BB0A8C1_0x004FDB00 | 56.3% | Od stack slot order differs SHC_3BB0A8C1_0x004FF080 | 0.0% | Pending From f1cb5c1219aee984024adfabd6ffb459eb59c0a3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:24 +0200 Subject: [PATCH 108/252] types: Unit+0x83 is a field, not padding 0x004F6FD0 triggerLoweredView writes a byte to Unit+0x83 right after setting heightDiv10, so the slot the header declared as padding_0x83[1] is a real field. Renamed to field_0x83; its meaning is still unknown. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/Units/Unit.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/Units/Unit.hpp b/src/OpenSHC/Map/Units/Unit.hpp index ea16549ee..3fe469fae 100644 --- a/src/OpenSHC/Map/Units/Unit.hpp +++ b/src/OpenSHC/Map/Units/Unit.hpp @@ -81,7 +81,7 @@ namespace Map { short gmIDUnk; // 0x0000007E length: 2 short displayColorPlayerID; // 0x00000080 length: 2 undefined1 heightDiv10; // 0x00000082 length: 1 - undefined1 padding_0x83[1]; // 0x00000083 length: 1 + undefined1 field_0x83; // 0x00000083 length: 1 short field58_0x84; // 0x00000084 length: 2 short field59_0x86; // 0x00000086 length: 2 short field60_0x88; // 0x00000088 length: 2 From 82a0eb2f2d56eabf3c046c77e71910ed6008ccae Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:36 +0200 Subject: [PATCH 109/252] reimplement: SHC_3BB0A8C1_0x004F6FD0 98.31% unit loop regalloc --- .../Map/TileMapState/triggerLoweredView.cpp | 66 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/triggerLoweredView.cpp diff --git a/src/OpenSHC/Map/TileMapState/triggerLoweredView.cpp b/src/OpenSHC/Map/TileMapState/triggerLoweredView.cpp new file mode 100644 index 000000000..cce058098 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/triggerLoweredView.cpp @@ -0,0 +1,66 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6FD0 + void TileMapState::triggerLoweredView(int param_1) + { + int view = 2; + if (this->flatViewToggleValue2 == 0) { + view = param_1; + } + if (this->refreshCertainTileMap_old == view) { + return; + } + this->counter1 = 0; + this->refreshCertainTileMap = view; + if (view != 3) { + return; + } + if (DAT_GameCore::instance.gamePausedLogical != 0) { + return; + } + + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) { + continue; + } + if (DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_DRUNK + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_RABBIT + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_HUNTERDOG + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_JESTER + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_CHICKEN + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_CHILD + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_JUGGLER + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_FIREEATER) { + continue; + } + + int height = (DAT_UnitsState::instance.units[unitID].buildingHeight + + DAT_UnitsState::instance.units[unitID].terrainOrClimbHeight) + / 10; + if (height > 14) { + height = 14; + } + DAT_UnitsState::instance.units[unitID].heightDiv10 = (char)height; + DAT_UnitsState::instance.units[unitID].field_0x83 = 0; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 75bb113f2..a3c7ebef1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38753,7 +38753,7 @@ SHC_3BB0A8C1_0x004F6DC0 | 0.0% | Pending SHC_3BB0A8C1_0x004F6F90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F6FD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6FD0 | 98.3% | unit loop regalloc SHC_3BB0A8C1_0x004F70B0 | 100.0% | Reimplemented From adb69cad77245d3cde90e5efb08a90aa2e23205a Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:36 +0200 Subject: [PATCH 110/252] reimplement: SHC_3BB0A8C1_0x004F9DF0 97.14% buildingType chain regalloc --- .../validateBuildingPlacementAtTile.cpp | 68 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/validateBuildingPlacementAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/validateBuildingPlacementAtTile.cpp b/src/OpenSHC/Map/TileMapState/validateBuildingPlacementAtTile.cpp new file mode 100644 index 000000000..407c0196b --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/validateBuildingPlacementAtTile.cpp @@ -0,0 +1,68 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9DF0 + void TileMapState::validateBuildingPlacementAtTile(int playerID, int x, int y) + { + this->buildingPlacementFail = FALSE; + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + int buildingID = this->BuildingLayer[tile]; + if (buildingID < 1 || (DAT_BuildingsState::instance.buildings[buildingID].owner != playerID && playerID != 0)) { + this->buildingPlacementFail = TRUE; + } + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 && this->BuildingLayer[tile] == 0) { + if ((this->WallOwnerLayer[tile] & 7) + 1 != playerID) { + return; + } + this->buildingPlacementFail = FALSE; + } + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_GATEHOUSESMALL + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_WOODGATE1 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_WOODGATE2 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KEEPDOOR + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_DRAWBRIDGE + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_CAMPGROUND + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_PARADEGROUND + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_PARADEGROUND2 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_PARADEGROUND3 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_PARADEGROUND4 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_PARADEGROUND5 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_CAMPFIRE + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT) { + this->buildingPlacementFail = TRUE; + } + this->field131_0x554954 = buildingID; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a3c7ebef1..143ba2b01 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39649,7 +39649,7 @@ SHC_3BB0A8C1_0x004F9DE9 | 0.0% | Pending SHC_3BB0A8C1_0x004F9DEA | 0.0% | Pending -SHC_3BB0A8C1_0x004F9DF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9DF0 | 97.1% | buildingType chain regalloc SHC_3BB0A8C1_0x004F9F00 | 0.0% | Pending From 902b5ebcf54cace0577667fc14d7add9e0d29b8c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:36 +0200 Subject: [PATCH 111/252] reimplement: SHC_3BB0A8C1_0x00501B90 75.00% orientation switch regalloc --- .../Map/TileMapState/changeMapOrientation.cpp | 62 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/changeMapOrientation.cpp diff --git a/src/OpenSHC/Map/TileMapState/changeMapOrientation.cpp b/src/OpenSHC/Map/TileMapState/changeMapOrientation.cpp new file mode 100644 index 000000000..07138d1e2 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/changeMapOrientation.cpp @@ -0,0 +1,62 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501B90 + void TileMapState::changeMapOrientation(int mapOrientation) + { + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::saveFocusTileAndCenterPreview, + DAT_ViewportRenderState::ptr)(); + this->mapOrientation = mapOrientation; + MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::restoreFocusTile, DAT_ViewportRenderState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::forceFullTileMapRedraw, this)(); + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::refreshAllBuildingTileDisplays, DAT_BuildingsState::ptr)(); + DAT_BuildingsState::instance.field4_0x10 = 5; + switch (this->mapOrientation) { + case 0: + this->field84_0x5548a4 = 3; + this->field88_0x5548b4 = 1; + this->field85_0x5548a8 = 2; + this->field86_0x5548ac = 4; + this->field87_0x5548b0 = 5; + return; + case 2: + this->field84_0x5548a4 = 5; + this->field88_0x5548b4 = 1; + this->field85_0x5548a8 = 4; + this->field86_0x5548ac = 6; + this->field87_0x5548b0 = 7; + return; + case 4: + this->field84_0x5548a4 = 7; + this->field85_0x5548a8 = 6; + this->field86_0x5548ac = 0; + this->field87_0x5548b0 = 1; + this->field88_0x5548b4 = -1; + return; + case 6: + this->field84_0x5548a4 = 1; + this->field85_0x5548a8 = 0; + this->field86_0x5548ac = 2; + this->field87_0x5548b0 = 3; + this->field88_0x5548b4 = -1; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 143ba2b01..8df85ff8f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41545,7 +41545,7 @@ SHC_3BB0A8C1_0x005017C0 | 0.0% | Pending SHC_3BB0A8C1_0x00501A20 | 0.0% | Pending -SHC_3BB0A8C1_0x00501B90 | 0.0% | Pending +SHC_3BB0A8C1_0x00501B90 | 75.0% | orientation switch regalloc SHC_3BB0A8C1_0x00501CB0 | 0.0% | Pending From abb7dc955e0e0758451cff6d838c8d64df3db96d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:37 +0200 Subject: [PATCH 112/252] reimplement: SHC_3BB0A8C1_0x004F9F00 72.99% microX/microY regalloc --- .../TileMapState/spawnEraserTileEffect.cpp | 67 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/spawnEraserTileEffect.cpp diff --git a/src/OpenSHC/Map/TileMapState/spawnEraserTileEffect.cpp b/src/OpenSHC/Map/TileMapState/spawnEraserTileEffect.cpp new file mode 100644 index 000000000..9f5fe0a8f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/spawnEraserTileEffect.cpp @@ -0,0 +1,67 @@ +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Entities::EntityType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9F00 + void TileMapState::spawnEraserTileEffect(undefined4 param_1, int tile) + { + uint y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int rowTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfbff; + if (this->UnitLayer[tile] != 0) { + return; + } + + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, DAT_EntityState::ptr)(tile); + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_BUILDING | L_STAIRS | L_UNKNOWN_WALL_RELATED + | L_CRENEL_VARIATIONUnk); + int microY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile] * 8; + int microX + = (tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] + .addXgetTile) + * 8; + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(0, 0, + 0, microX, microY, this->DefaultHeightLayer[tile], microX + 1, microY + 1, this->DefaultHeightLayer[tile], + (EntityType)0x1e, 0); + this->BuildingWasLayer[tile] = 0; + this->DamageLayer[tile] = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(9, tile - rowTile, y); + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8df85ff8f..8ab2384e2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39651,7 +39651,7 @@ SHC_3BB0A8C1_0x004F9DEA | 0.0% | Pending SHC_3BB0A8C1_0x004F9DF0 | 97.1% | buildingType chain regalloc -SHC_3BB0A8C1_0x004F9F00 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9F00 | 73.0% | microX/microY regalloc SHC_3BB0A8C1_0x004FA000 | 0.0% | Pending From 6e046ae73f1556c4ac1f90196f537ca8dc6440f5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:37 +0200 Subject: [PATCH 113/252] reimplement: SHC_3BB0A8C1_0x00507130 53.09% setupBuildingData arg regalloc --- src/OpenSHC/Map/TileMapState/placeTower.cpp | 62 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeTower.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeTower.cpp b/src/OpenSHC/Map/TileMapState/placeTower.cpp new file mode 100644 index 000000000..dbb3f9633 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeTower.cpp @@ -0,0 +1,62 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507130 + void TileMapState::placeTower( + int param_1, uint param_2, uint param_3, undefined4 param_4, uint size, int param_6, undefined4 param_7) + { + int uniqueID = DAT_GameCore::instance.uniqueGameObjectTracker; + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, param_2, param_3, param_7, (BuildingType)(short)param_4, size, param_1, param_6); + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = uniqueID; + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + param_2 + this->buildingX; + if (index < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[index] = tile; + } + this->HeightLayer[tile] = (byte)param_7; + if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[size][0] == index) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[size][1] == index) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[size][2] == index) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } else if (DAT_TerrainDefinedData::instance.TowerTileOffsetsBySize[size][3] == index) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_KEEP_NON_MANOR_HOUSE; + } + this->BuildingLayer[tile] = (short)buildingID; + index++; + this->BuildingWasLayer[tile] = (uchar)param_4; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8ab2384e2..6c4a735bf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42095,7 +42095,7 @@ SHC_3BB0A8C1_0x00506F40 | 0.0% | Pending SHC_3BB0A8C1_0x00507060 | 90.8% | setupBuildingData arg regalloc -SHC_3BB0A8C1_0x00507130 | 0.0% | Pending +SHC_3BB0A8C1_0x00507130 | 53.1% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00507280 | 54.5% | ecx not kept across callee From 8d9fe6f4a549f3777b7b2cd8711ae35ef9f49197 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:37 +0200 Subject: [PATCH 114/252] reimplement: SHC_3BB0A8C1_0x00507560 44.83% setupBuildingData arg regalloc --- .../Map/TileMapState/placeGatehouseLarge.cpp | 62 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeGatehouseLarge.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeGatehouseLarge.cpp b/src/OpenSHC/Map/TileMapState/placeGatehouseLarge.cpp new file mode 100644 index 000000000..13eb06d5e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeGatehouseLarge.cpp @@ -0,0 +1,62 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507560 + void TileMapState::placeGatehouseLarge( + int param_1, uint param_2, uint param_3, undefined4 param_4, uint param_5, int param_6, undefined4 param_7) + { + int uniqueID = DAT_GameCore::instance.uniqueGameObjectTracker; + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, param_2, param_3, param_7, (BuildingType)(short)param_4, param_5, param_1, param_6); + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = uniqueID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_5); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + param_2 + this->buildingX; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (char)param_7 + 0x5a; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_WALL_OR_GATEHOUSE; + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | (char)param_1 - 1U; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x20; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->BuildingWasLayer[tile] = (uchar)param_4; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + + int climbVariant = 0; + if (param_6 == 0x50) { + climbVariant = 2; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::createClimbData, DAT_PathFindingState::ptr)( + 3, buildingID, 0, climbVariant, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6c4a735bf..d9e209b46 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42137,7 +42137,7 @@ SHC_3BB0A8C1_0x0050741E | 0.0% | Pending SHC_3BB0A8C1_0x00507420 | 0.0% | Pending -SHC_3BB0A8C1_0x00507560 | 0.0% | Pending +SHC_3BB0A8C1_0x00507560 | 44.8% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x005076A0 | 0.0% | Pending From 965a7e0ed885e6c7ecc51f1cb54aa4965aef910e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 11:44:38 +0200 Subject: [PATCH 115/252] reimplement: SHC_3BB0A8C1_0x00507420 44.83% setupBuildingData arg regalloc --- .../Map/TileMapState/placeGatehouseSmall.cpp | 62 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeGatehouseSmall.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeGatehouseSmall.cpp b/src/OpenSHC/Map/TileMapState/placeGatehouseSmall.cpp new file mode 100644 index 000000000..78a745e03 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeGatehouseSmall.cpp @@ -0,0 +1,62 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00507420 + void TileMapState::placeGatehouseSmall( + int param_1, uint param_2, uint param_3, undefined4 param_4, uint param_5, int param_6, undefined4 param_7) + { + int uniqueID = DAT_GameCore::instance.uniqueGameObjectTracker; + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + param_1, param_2, param_3, param_7, (BuildingType)(short)param_4, param_5, param_1, param_6); + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = uniqueID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, param_5); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + param_3].addXgetTile + + param_2 + this->buildingX; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (char)param_7 + 0x5a; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_WALL_OR_GATEHOUSE; + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | (char)param_1 - 1U; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x20; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->BuildingWasLayer[tile] = (uchar)param_4; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + + int climbVariant = 0; + if (param_6 == 0x50) { + climbVariant = 2; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::createClimbData, DAT_PathFindingState::ptr)( + 4, buildingID, 0, climbVariant, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d9e209b46..2de336020 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42135,7 +42135,7 @@ SHC_3BB0A8C1_0x0050741D | 0.0% | Pending SHC_3BB0A8C1_0x0050741E | 0.0% | Pending -SHC_3BB0A8C1_0x00507420 | 0.0% | Pending +SHC_3BB0A8C1_0x00507420 | 44.8% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00507560 | 44.8% | setupBuildingData arg regalloc From c965d32e2151d75580c54a80606da22729fbacdc Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:06:57 +0200 Subject: [PATCH 116/252] types: name Logic1 bit 0x40 0x00512940 setTerrain both tests flags1 against 0x40 and sets that bit on the tile, so it is a real Logic1 flag the generated enum was missing. Ghidra had to render the test as flags1 == ~(every other Logic1 value OR'd together), which is how the gap shows up in decompiled output. Named L_UNNAMED_0x40 since its meaning is not known yet; rename once it is. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/LogicHelpers/Logic1.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OpenSHC/Map/LogicHelpers/Logic1.hpp b/src/OpenSHC/Map/LogicHelpers/Logic1.hpp index b1b0e4dfe..6f621f3bf 100644 --- a/src/OpenSHC/Map/LogicHelpers/Logic1.hpp +++ b/src/OpenSHC/Map/LogicHelpers/Logic1.hpp @@ -20,6 +20,7 @@ namespace Map { L_PLAIN2_AND_PITCH = 8, // 0x00000008 L_BORDER = 16, // 0x00000010 L_BORDER_EDGE = 32, // 0x00000020 + L_UNNAMED_0x40 = 64, // 0x00000040 L_ROCKY = 128, // 0x00000080 L_WALL_OR_GATEHOUSE = 256, // 0x00000100 L_CRENEL = 512, // 0x00000200 From 4d3549255721240d1c2299036c3d81062b06f7c4 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:07:07 +0200 Subject: [PATCH 117/252] reimplement: SHC_3BB0A8C1_0x00512940 75.99% Od stack slot order differs --- src/OpenSHC/Map/TileMapState/setTerrain.cpp | 447 ++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setTerrain.cpp diff --git a/src/OpenSHC/Map/TileMapState/setTerrain.cpp b/src/OpenSHC/Map/TileMapState/setTerrain.cpp new file mode 100644 index 000000000..3b1a9bae2 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setTerrain.cpp @@ -0,0 +1,447 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/TileMapState/NeighbourFlagsAsm.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +// mask for the handwritten neighbour-flag macro; MASM has no "|", so this must be a literal +#define NEIGHBOUR_FLAGS_MASK_L2_BEACH 0x20 // L2_BEACH + +#pragma optimize("", off) + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::LogicHelpers::L2_BEACH; + using OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + using OpenSHC::Map::LogicHelpers::L2_MOAT_UNDUG; + using OpenSHC::Map::LogicHelpers::L2_NONE; + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_SCRUB; + using OpenSHC::Map::LogicHelpers::L2_STONES_OR_DRIVEN_SANDUnk; + using OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_NONE; + using OpenSHC::Map::LogicHelpers::L_OIL; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_UNNAMED_0x40; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00512940 + void TileMapState::setTerrain(int playerID, int tile, uint yParam, uint brushType, Logic1 flags1, Logic2 flags2) + { + /* + Holds one expansion of the handwritten neighbour-flag macro (see NeighbourFlagsAsm.hpp), + so the original was built without optimisation and the pragma above is needed to reproduce + its frame-pointer, reload-per-access shape. The locals are declared together because at + /Od the stack slots are observable and MSVC assigns them per function, not per scope. + + L_UNNAMED_0x40 is the one Logic1 bit the generated enum has no name for; the original both + tests flags1 against it and sets it on the tile. + */ + int baseTile; + uint baseY; + uint x; + int moatEnemyRange; + int moatOpponentRange; + int index; + int size; + + size = DAT_TerrainDefinedData::instance.BrushSizeArray[brushType]; + baseTile = tile; + baseY = yParam; + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + moatEnemyRange = 0xf; + moatOpponentRange = 7; + } else { + moatEnemyRange = 0x1e; + moatOpponentRange = 0x1e; + } + + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_EDITOR && flags1 != L_MOAT + && (flags2 == L2_EARTH_AND_STONES || flags2 == L2_OASIS_GRASS || flags2 == L2_BEACH + || flags2 == L2_STONES_OR_DRIVEN_SANDUnk || flags2 == L2_SCRUB || flags2 == L2_THICK_SCRUB)) { + /* + this functions processes all oasis tiles + */ + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setLand, this)(tile, yParam, brushType); + } + if (flags1 == L_MOAT) { + size = 9; + } + + for (index = 0; index < size; index++) { + if (flags1 == L_MOAT) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 0, index, &tile, (int*)&yParam, baseTile, baseY); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, &tile, (int*)&yParam, baseTile, baseY); + } + if ((this->LogicLayer[tile] & L_BORDER) != 0) { + continue; + } + + if (flags1 == L_SEA) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || this->OrganismLayer[tile] != 0) { + continue; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PEBBLES; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_SEA; + this->HeightLayer[tile] = 0; + this->DefaultHeightLayer[tile] = 0; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + } else if (flags1 == L_RIVER || flags1 == L_FORD) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || this->OrganismLayer[tile] != 0) { + continue; + } + if (flags2 != L2_NONE && (this->LogicLayer[tile] & L_RIVER) == 0) { + continue; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + if (flags1 == L_RIVER) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PEBBLES; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + if (flags2 != L2_BEACH) { + this->WallGFXLayer[tile] = this->RandomLayer[tile] & 7; + } + if (flags2 == L2_OASIS_GRASS) { + this->Logic2Layer[tile] = L2_OASIS_GRASS; + } + if (flags2 == L2_BEACH) { + this->Logic2Layer[tile] = L2_BEACH; + this->WallGFXLayer[tile] = ((ushort)DAT_GameCore::instance.mapTimeInTicks & 8) + + this->WallGFXLayer[tile] * 0x20 + (this->RandomLayer[tile] & 7) * 0x400; + } + this->LogicLayer[tile] = this->LogicLayer[tile] | flags1; + if (this->HeightLayer[tile] > 7) { + this->HeightLayer[tile] = this->DefaultHeightLayer[tile] - 8; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + } + } else if (flags1 == L_ROCKY) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_RIVER) != 0 || this->OrganismLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & L_SEA) == 0) { + if (this->HeightLayer[tile] < 8) { + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + } + } else { + this->HeightLayer[tile] = 0; + this->DefaultHeightLayer[tile] = 0; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PEBBLES; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_ROCKY; + } else if (flags1 == L_IRON) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_SEA) != 0 || (this->LogicLayer[tile] & L_RIVER) != 0 + || this->OrganismLayer[tile] != 0) { + continue; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PEBBLES; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_IRON; + } else if (flags1 == L_PEBBLES) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_RIVER) != 0 || this->OrganismLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & L_SEA) == 0) { + if (this->HeightLayer[tile] < 8) { + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + } + } else { + this->HeightLayer[tile] = 0; + this->DefaultHeightLayer[tile] = 0; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_PEBBLES; + } else if (flags1 == L_MARSH) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_RIVER) != 0 || this->OrganismLayer[tile] != 0) { + continue; + } + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_MARSH; + } else if (flags1 == L_OIL) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_RIVER) != 0 || this->OrganismLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & L_MARSH) == 0) { + continue; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_OIL; + } else if (flags1 == L_MOAT) { + if (this->OrganismLayer[tile] != 0 + || (this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_SEA) != 0 || (this->LogicLayer[tile] & L_RIVER) != 0 + || (this->LogicLayer[tile] & L_FORD) != 0 || (this->LogicLayer[tile] & L_ROCKY) != 0 + || (this->LogicLayer[tile] & L_BOULDERS) != 0 || (this->LogicLayer[tile] & L_IRON) != 0 + || (this->LogicLayer[tile] & L_MARSH) != 0 || (this->LogicLayer[tile] & L_PLAIN1_AND_FARM) != 0) { + continue; + } + x = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::computeTileXOffset, + DAT_ViewportRenderState::ptr)(tile, yParam); + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, x, yParam, moatEnemyRange) + != FALSE) { + continue; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, + DAT_PathFindingState::ptr)(playerID, x, yParam, moatOpponentRange, -1, -1, + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getCastleBuildRangeForMapSize, this)() + + 5) + != 0) { + continue; + } + } + if ((this->LogicLayer[tile] & L_MOAT) != 0 && flags2 != L2_MOAT_UNDUG) { + continue; + } + if (this->HeightLayer[tile] >= 0xd) { + continue; + } + if (flags2 == L2_NONE) { + if ((this->LogicLayer[tile] & L_MOAT_DUG_OR_PLANNED) == 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::createMoatData, this)( + playerID, x, yParam, 0) + != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_MOAT_DUG_OR_PLANNED; + } + } else if (flags2 == L2_SCRUB) { + if ((this->LogicLayer[tile] & L_MOAT_DUG_OR_PLANNED) != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT_DUG_OR_PLANNED; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(x, yParam); + } + } else { + this->HeightLayer[tile] = 8; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + if (flags2 == L2_EARTH_AND_STONES) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::createMoatData, this)( + playerID, x, yParam, 1) + != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT_DUG_OR_PLANNED; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_MOAT; + this->HeightLayer[tile] = 0; + } + } else if (flags2 == L2_MOAT_UNDUG) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(x, yParam); + this->HeightLayer[tile] = 8; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT_DUG_OR_PLANNED; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + } + } + } else if (flags2 != L2_EARTH_AND_STONES && flags2 != L2_OASIS_GRASS && flags2 != L2_BEACH + && flags2 != L2_STONES_OR_DRIVEN_SANDUnk && flags2 != L2_SCRUB && flags2 != L2_THICK_SCRUB) { + if (flags1 == L_BOULDERS) { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & L_RIVER) != 0 || this->OrganismLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & L_SEA) == 0) { + if (this->HeightLayer[tile] < 8) { + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + } + } else { + this->HeightLayer[tile] = 0; + this->DefaultHeightLayer[tile] = 0; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PEBBLES; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BOULDERS; + } else if (flags1 == L_UNNAMED_0x40) { + if ((this->LogicLayer[tile] & L_SEA) == 0 + || (this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || this->OrganismLayer[tile] != 0) { + continue; + } + this->LogicLayer[tile] = this->LogicLayer[tile] | L_UNNAMED_0x40; + } + } else { + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + || this->BuildingLayer[tile] != 0 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0 + || (this->LogicLayer[tile] & (L_SEA | L_RIVER | L_FORD | L_MARSH | L_MOAT)) != 0 + || this->OrganismLayer[tile] != 0) { + continue; + } + if (flags2 == L2_EARTH_AND_STONES) { + if ((this->LogicLayer[tile] & L_IRON) != 0 || (this->LogicLayer[tile] & L_BOULDERS) != 0 + || (this->Logic2Layer[tile] & L2_BEACH) != 0) { + continue; + } + MACRO_NEIGHBOUR_FLAGS_TERRAIN_8(1, NEIGHBOUR_FLAGS_MASK_L2_BEACH) + if (this->bitFlag != 0) { + continue; + } + } + + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffdf; + if (flags2 != L2_STONES_OR_DRIVEN_SANDUnk && flags2 != L2_SCRUB && flags2 != L2_THICK_SCRUB + && flags2 != L2_EARTH_AND_STONES && flags2 != L2_OASIS_GRASS) { + if (flags2 == L2_BEACH) { + this->HeightLayer[tile] = 0; + this->DefaultHeightLayer[tile] = 0; + } else { + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + } + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_SEA; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_UNNAMED_0x40; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_RIVER; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_FORD; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_BOULDERS; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_IRON; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MARSH; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_OIL; + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_MOAT; + if (flags2 != L2_EARTH_AND_STONES) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + } + this->Logic2Layer[tile] = (byte)flags2; + } + + if (flags1 != L_NONE) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(yParam, tile); + } + } + } + +} +} + +#pragma optimize("", on) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2de336020..eeadbb4c5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44741,7 +44741,7 @@ SHC_3BB0A8C1_0x005127D0 | 0.0% | Pending SHC_3BB0A8C1_0x00512920 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00512940 | 0.0% | Pending +SHC_3BB0A8C1_0x00512940 | 76.0% | Od stack slot order differs SHC_3BB0A8C1_0x00514480 | 40.0% | logic masks merged by cl From aa466640ef01598660efed05e91d3959d2e066e0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:08:36 +0200 Subject: [PATCH 118/252] reimplement: SHC_3BB0A8C1_0x004FAB70 70.40% ecx not kept across callee --- .../clearBuildingFootprintAndResetUnits.cpp | 65 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndResetUnits.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndResetUnits.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndResetUnits.cpp new file mode 100644 index 000000000..c0280b2c9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingFootprintAndResetUnits.cpp @@ -0,0 +1,65 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FAB70 + void TileMapState::clearBuildingFootprintAndResetUnits(int x, int y, int size) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_BUILDING | L_STAIRS | L_CRENEL_VARIATIONUnk + | L_KEEP_NON_MANOR_HOUSE); + if ((this->MiscDisplayLayer[tile] & 0x20) != 0) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffdf; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + } + short buildingID = this->BuildingLayer[tile]; + this->BuildingLayer[tile] = 0; + if (DAT_BuildingsState::instance.buildings[buildingID].noRubble == 0) { + this->BuildingWasLayer[tile] = 0; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isFootprintIndexOnEdge, this)( + buildingSizeTileIndex, size) + == FALSE) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x4000; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x2000; + } + for (short unitID = this->UnitLayer[tile]; unitID != 0; + unitID = DAT_UnitsState::instance.units[unitID].nextUnitOnTheSameTile) { + DAT_UnitsState::instance.units[unitID].vanish = 0; + DAT_UnitsState::instance.units[unitID].unknownCountdown_0x402 = 0; + } + buildingSizeTileIndex++; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index eeadbb4c5..b5efd4058 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40355,7 +40355,7 @@ SHC_3BB0A8C1_0x004FAAB0 | 0.0% | Pending SHC_3BB0A8C1_0x004FAAE0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FAB70 | 0.0% | Pending +SHC_3BB0A8C1_0x004FAB70 | 70.4% | ecx not kept across callee SHC_3BB0A8C1_0x004FAC70 | 84.7% | ecx not kept across callee From f98c394cfd50db48e2786f552fa445fbd3094299 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:41:02 +0200 Subject: [PATCH 119/252] reimplement: SHC_3BB0A8C1_0x004FC340 62.42% LogicLayer walk regalloc --- .../collectCliffEdgeTilesForClimbData.cpp | 67 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/collectCliffEdgeTilesForClimbData.cpp diff --git a/src/OpenSHC/Map/TileMapState/collectCliffEdgeTilesForClimbData.cpp b/src/OpenSHC/Map/TileMapState/collectCliffEdgeTilesForClimbData.cpp new file mode 100644 index 000000000..488778c2b --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/collectCliffEdgeTilesForClimbData.cpp @@ -0,0 +1,67 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ClimbLogicDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH; + using OpenSHC::Map::LogicHelpers::L2_STONES_OR_DRIVEN_SANDUnk; + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_SEA; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC340 + void TileMapState::collectCliffEdgeTilesForClimbData() + { + this->temporaryTerrainTypeIndex = 0; + for (int tile = 0; tile < 80400; tile++) { + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + continue; + } + + if ((this->LogicLayer[tile] & L_RIVER) != 0 + && (this->Logic2Layer[tile] & L2_STONES_OR_DRIVEN_SANDUnk) != 0) { + this->temporaryTerrainTypeBinaryArray[this->temporaryTerrainTypeIndex] = 1; + this->temporaryTerrainTypeArray[this->temporaryTerrainTypeIndex] = tile; + for (int index = 0; index < 8; index++) { + int neighbour + = this->directionTranslationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[tile]] + [DAT_ClimbLogicDefinedData::instance.field5_0x2c[index]] + + tile; + if ((this->LogicLayer[neighbour] & L_RIVER) != 0 + && this->HeightLayer[tile] + 0x50 < (uint)this->HeightLayer[neighbour]) { + this->temporaryTerrainTypeBinaryArray[this->temporaryTerrainTypeIndex] = 0; + break; + } + } + this->temporaryTerrainTypeIndex = this->temporaryTerrainTypeIndex + 1; + if ((int)this->temporaryTerrainTypeIndex > 999) { + return; + } + } + + if (((this->LogicLayer[tile] & L_RIVER) != 0 && (this->Logic2Layer[tile] & L2_OASIS_GRASS) != 0) + || ((this->LogicLayer[tile] & L_SEA) != 0 && (this->Logic2Layer[tile] & L2_PLATEAU_HIGH) != 0)) { + this->temporaryTerrainTypeBinaryArray[this->temporaryTerrainTypeIndex] = 1; + this->temporaryTerrainTypeArray[this->temporaryTerrainTypeIndex] = tile; + this->temporaryTerrainTypeIndex = this->temporaryTerrainTypeIndex + 1; + if ((int)this->temporaryTerrainTypeIndex > 999) { + return; + } + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b5efd4058..1233a3c22 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41085,7 +41085,7 @@ SHC_3BB0A8C1_0x004FC0B0 | 0.0% | Pending SHC_3BB0A8C1_0x004FC280 | 85.2% | XYPair base regalloc -SHC_3BB0A8C1_0x004FC340 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC340 | 62.4% | LogicLayer walk regalloc SHC_3BB0A8C1_0x004FC490 | 0.0% | Pending From e29527c04ba39b7a7e1019e56a85c89262eef73b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:41:02 +0200 Subject: [PATCH 120/252] reimplement: SHC_3BB0A8C1_0x004FBD80 38.67% brush step regalloc --- .../Map/TileMapState/getTileForBrush.cpp | 65 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getTileForBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/getTileForBrush.cpp b/src/OpenSHC/Map/TileMapState/getTileForBrush.cpp new file mode 100644 index 000000000..52712f1e2 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getTileForBrush.cpp @@ -0,0 +1,65 @@ +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FBD80 + void TileMapState::getTileForBrush(int square, int index, int* tilePointer, int* yPointer, int baseTile, uint y) + { + if (square != 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::getTileInSquareBrush, DAT_PathFindingState::ptr)( + index, baseTile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile, y); + *tilePointer = DAT_PathFindingState::instance.resultTile; + *yPointer = DAT_PathFindingState::instance.resultY; + return; + } + + if (index > 37) { + index = 0; + } + int brushStep = DAT_TerrainDefinedData::instance.field12_0xc[index]; + if (brushStep == 0xf) { + return; + } + if (brushStep < 8) { + *tilePointer = *tilePointer + this->directionTranslationMatrix[*yPointer][brushStep]; + *yPointer = *yPointer + + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[brushStep].int_.yOffset; + return; + } + + int direction; + if (brushStep < 28) { + direction = brushStep + 20; + brushStep = this->directionTranslationMatrix[*yPointer - 3][brushStep + 4]; + } else { + if (brushStep > 48) { + return; + } + direction = brushStep + 40; + *tilePointer = *tilePointer + this->directionTranslationMatrix[*yPointer][direction]; + *yPointer = *yPointer + DAT_TerrainDefinedData::instance.field12_0xc[brushStep * 2 - 0x15]; + brushStep = this->directionTranslationMatrix[*yPointer][direction]; + } + *tilePointer = *tilePointer + brushStep; + *yPointer + = *yPointer + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction].int_.yOffset; + *tilePointer = *tilePointer + this->directionTranslationMatrix[*yPointer][direction]; + *yPointer + = *yPointer + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction].int_.yOffset; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1233a3c22..f1f1e334f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41077,7 +41077,7 @@ SHC_3BB0A8C1_0x004FBD6F | 0.0% | Pending SHC_3BB0A8C1_0x004FBD70 | 0.0% | Pending -SHC_3BB0A8C1_0x004FBD80 | 0.0% | Pending +SHC_3BB0A8C1_0x004FBD80 | 38.7% | brush step regalloc SHC_3BB0A8C1_0x004FBE70 | 0.0% | Pending From 5bd5f33592295650c037ad9f57e3bcd22f251802 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:41:03 +0200 Subject: [PATCH 121/252] reimplement: SHC_3BB0A8C1_0x004FA550 100.00% Reimplemented --- .../getBuildingSizeForCommandBuildingType.cpp | 228 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getBuildingSizeForCommandBuildingType.cpp diff --git a/src/OpenSHC/Map/TileMapState/getBuildingSizeForCommandBuildingType.cpp b/src/OpenSHC/Map/TileMapState/getBuildingSizeForCommandBuildingType.cpp new file mode 100644 index 000000000..eb8862e2c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getBuildingSizeForCommandBuildingType.cpp @@ -0,0 +1,228 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA550 + int TileMapState::getBuildingSizeForCommandBuildingType(MappersEnum commandBuildingType) + { + /* + The original dispatches through a byte index table at 0x004FA614 (0x147 entries, biased by + M_MAPPER_UNDUGMOAT) into a jump table at 0x004FA5DC, which is what MSVC emits for a dense + switch; Ghidra could not normalise it and rendered the dispatch as a read through an + unnamed pointer array. The case groups below are that byte table, decoded. + + field159_0x5549b8 is written through the global instance, not through this, which is how + the original addresses it. + */ + switch (commandBuildingType) { + case OpenSHC::Commands::M_MAPPER_FLETCHER: + case OpenSHC::Commands::M_MAPPER_HOVEL: + case OpenSHC::Commands::M_MAPPER_BAKER: + case OpenSHC::Commands::M_MAPPER_BREWER: + case OpenSHC::Commands::M_MAPPER_GRANARY: + case OpenSHC::Commands::M_MAPPER_ARMOURY: + case OpenSHC::Commands::M_MAPPER_POLETURNER: + case OpenSHC::Commands::M_MAPPER_BLACKSMITH: + case OpenSHC::Commands::M_MAPPER_ARMOURER: + case OpenSHC::Commands::M_MAPPER_TANNER: + case OpenSHC::Commands::M_MAPPER_IRON_MINE: + case OpenSHC::Commands::M_MAPPER_PITCH_WORKINGS: + case OpenSHC::Commands::M_MAPPER_TOWER2: + case OpenSHC::Commands::M_MAPPER_GARDEN10: + case OpenSHC::Commands::M_MAPPER_GARDEN11: + case OpenSHC::Commands::M_MAPPER_GARDEN12: + case OpenSHC::Commands::M_MAPPER_OIL_SMELTER: + case (MappersEnum)258: + case (MappersEnum)259: + case (MappersEnum)260: + case OpenSHC::Commands::M_MAPPER_WATERPOT: + return 4; + case OpenSHC::Commands::M_MAPPER_STORES: + case OpenSHC::Commands::M_MAPPER_TRADEPOST: + case OpenSHC::Commands::M_MAPPER_BARRACKS_EURO: + case OpenSHC::Commands::M_MAPPER_BARRACKS_ARAB: + case OpenSHC::Commands::M_MAPPER_ENGINEERS_GUILD: + case OpenSHC::Commands::M_MAPPER_TUNNELERS_GUILD: + case OpenSHC::Commands::M_MAPPER_INN: + case OpenSHC::Commands::M_MAPPER_GATE_INNER: + case OpenSHC::Commands::M_MAPPER_DRAWBRIDGE: + case OpenSHC::Commands::M_MAPPER_TOWER3: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1B: + case OpenSHC::Commands::M_MAPPER_OUTPOST_EURO: + case OpenSHC::Commands::M_MAPPER_OUTPOST_ARAB: + case OpenSHC::Commands::M_MAPPER_CESS_PIT1: + case OpenSHC::Commands::M_MAPPER_CESS_PIT2: + case OpenSHC::Commands::M_MAPPER_CESS_PIT3: + case OpenSHC::Commands::M_MAPPER_CESS_PIT4: + case OpenSHC::Commands::M_MAPPER_DUNGEON: + case OpenSHC::Commands::M_MAPPER_DUNKING_STOOL: + case OpenSHC::Commands::M_MAPPER_DANCING_BEAR: + case OpenSHC::Commands::M_MAPPER_POND1: + case OpenSHC::Commands::M_MAPPER_POND2_SMALL: + return 5; + case OpenSHC::Commands::M_MAPPER_QUARRY: + case OpenSHC::Commands::M_MAPPER_STABLES: + case OpenSHC::Commands::M_MAPPER_HEALER: + case OpenSHC::Commands::M_MAPPER_CHURCH1: + case OpenSHC::Commands::M_MAPPER_TOWER4: + case OpenSHC::Commands::M_MAPPER_TOWER5: + case OpenSHC::Commands::M_MAPPER_POND3_LARGE1: + case OpenSHC::Commands::M_MAPPER_POND4_LARGE2: + return 6; + case OpenSHC::Commands::M_MAPPER_WOODSMAN: + case OpenSHC::Commands::M_MAPPER_TUNNEL: + case OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION: + case OpenSHC::Commands::M_MAPPER_MILL: + case OpenSHC::Commands::M_MAPPER_HUNTER: + case OpenSHC::Commands::M_MAPPER_TOWER1: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1A: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1B: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1C: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1D: + case OpenSHC::Commands::M_MAPPER_GARDEN7: + case OpenSHC::Commands::M_MAPPER_GARDEN8: + case OpenSHC::Commands::M_MAPPER_GARDEN9: + case OpenSHC::Commands::M_MAPPER_MAYPOLE: + case OpenSHC::Commands::M_MAPPER_STOCKS: + case OpenSHC::Commands::M_MAPPER_CATAPULT: + case OpenSHC::Commands::M_MAPPER_TREBUCHET: + case OpenSHC::Commands::M_MAPPER_SIEGE_TOWER: + case OpenSHC::Commands::M_MAPPER_BATTERING_RAM: + case OpenSHC::Commands::M_MAPPER_PORTABLE_SHIELD: + case OpenSHC::Commands::M_MAPPER_BURNING_STAKE: + case OpenSHC::Commands::M_MAPPER_RACK_STRETCHING: + case OpenSHC::Commands::M_MAPPER_CHOPPING_BLOCK: + case OpenSHC::Commands::M_MAPPER_DOG_CAGE: + case OpenSHC::Commands::M_MAPPER_WELL: + case OpenSHC::Commands::M_MAPPER_ARAB_BALLISTA: + return 3; + case OpenSHC::Commands::M_MAPPER_KEEP1: + case OpenSHC::Commands::M_MAPPER_KEEP2: + case OpenSHC::Commands::M_MAPPER_GATE_MAIN: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2B: + return 7; + case OpenSHC::Commands::M_MAPPER_CAMP_FIRE: + case OpenSHC::Commands::M_MAPPER_KILLING_PIT: + case OpenSHC::Commands::M_MAPPER_PITCH_DITCH: + case (MappersEnum)248: + case (MappersEnum)249: + case (MappersEnum)250: + case (MappersEnum)251: + case OpenSHC::Commands::M_MAPPER_SHRINE5: + return 1; + case OpenSHC::Commands::M_MAPPER_KEEP3: + case OpenSHC::Commands::M_MAPPER_APPLEFARM: + return 0xb; + case OpenSHC::Commands::M_MAPPER_WHEATFARM: + case OpenSHC::Commands::M_MAPPER_HOPSFARM: + case OpenSHC::Commands::M_MAPPER_CHURCH2: + return 9; + case OpenSHC::Commands::M_MAPPER_CHURCH3: + return 0xd; + case OpenSHC::Commands::M_MAPPER_CATTLEFARM: + return 0xa; + case OpenSHC::Commands::M_MAPPER_UNDUGMOAT: + case OpenSHC::Commands::M_MAPPER_DUGMOAT: + case OpenSHC::Commands::M_MAPPER_MOAT: + case OpenSHC::Commands::M_MAPPER_ANTIMOAT: + DAT_TileMapState::instance.field159_0x5549b8 = 1; + return 2; + case OpenSHC::Commands::M_MAPPER_OXENBASE: + case OpenSHC::Commands::M_MAPPER_SIGNPOST: + case OpenSHC::Commands::M_MAPPER_GATE_POSTERN: + case OpenSHC::Commands::M_MAPPER_GARDEN1: + case OpenSHC::Commands::M_MAPPER_GARDEN2: + case OpenSHC::Commands::M_MAPPER_GARDEN3: + case OpenSHC::Commands::M_MAPPER_GARDEN4: + case OpenSHC::Commands::M_MAPPER_GARDEN5: + case OpenSHC::Commands::M_MAPPER_GARDEN6: + case OpenSHC::Commands::M_MAPPER_GALLOWS: + case (MappersEnum)252: + case (MappersEnum)253: + case (MappersEnum)254: + case (MappersEnum)255: + case (MappersEnum)256: + case (MappersEnum)257: + case OpenSHC::Commands::M_MAPPER_GIBBET: + case OpenSHC::Commands::M_MAPPER_STATUE1: + case OpenSHC::Commands::M_MAPPER_STATUE2: + case OpenSHC::Commands::M_MAPPER_STATUE3: + case OpenSHC::Commands::M_MAPPER_STATUE4: + case OpenSHC::Commands::M_MAPPER_STATUE5: + case OpenSHC::Commands::M_MAPPER_SHRINE1: + case OpenSHC::Commands::M_MAPPER_SHRINE2: + case OpenSHC::Commands::M_MAPPER_SHRINE3: + case OpenSHC::Commands::M_MAPPER_SHRINE4: + return 2; + case OpenSHC::Commands::M_MAPPER_FLAG_TYPE0: + case OpenSHC::Commands::M_MAPPER_FLAG_TYPE1: + case OpenSHC::Commands::M_MAPPER_FLAG_TYPE2: + case OpenSHC::Commands::M_MAPPER_FLAG_TYPE3: + case OpenSHC::Commands::M_MAPPER_HEADS: + case OpenSHC::Commands::M_MAPPER_BRAZIER: + case OpenSHC::Commands::M_MAPPER_MANGONEL: + case OpenSHC::Commands::M_MAPPER_BALLISTA: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARCHERS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_SPEARMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_PIKEMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_MACEMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_XBOWMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_SWORDSMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_KNIGHTS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_LADDERMEN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ENGINEERS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ENGINEERS_POTS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_MONKS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_CATAPULTS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_TREBUCHETS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_BATTERING_RAMS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_SIEGE_TOWERS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_PORTABLE_SHIELDS: + case OpenSHC::Commands::M_MAPPER_PEOPLE_TUNNELERS: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT1: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT2: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT3: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT4: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT5: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT6: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINT7: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_BOW: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_SLAVE: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_SLINGER: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_ASSASIN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_HORSEMAN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_SWORDSMAN: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_GRENADIER: + case OpenSHC::Commands::M_MAPPER_PEOPLE_ARAB_BALLISTA: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM1: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM2: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM3: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM4: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM5: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM6: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTM7: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTE1: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTE2: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTT1: + case OpenSHC::Commands::M_MAPPER_PLACE_ASSEMBLY_POINTK1: + return 0; + } + return -1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f1f1e334f..ccdcdde5b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39659,7 +39659,7 @@ SHC_3BB0A8C1_0x004FA2D0 | 0.0% | Pending SHC_3BB0A8C1_0x004FA460 | 0.0% | Pending -SHC_3BB0A8C1_0x004FA550 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA550 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004FA5DC | 0.0% | Pending From d09e55af4e1bbe8961d0145f29547097c7299fc6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:55:46 +0200 Subject: [PATCH 122/252] reimplement: SHC_3BB0A8C1_0x00506F40 85.19% setupBuildingData arg regalloc --- .../TileMapState/placePositiveFearfactor.cpp | 67 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placePositiveFearfactor.cpp diff --git a/src/OpenSHC/Map/TileMapState/placePositiveFearfactor.cpp b/src/OpenSHC/Map/TileMapState/placePositiveFearfactor.cpp new file mode 100644 index 000000000..22e644faa --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placePositiveFearfactor.cpp @@ -0,0 +1,67 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506F40 + void TileMapState::placePositiveFearfactor(int playerID, uint x, uint y, undefined4 buildingType, + undefined4 variation, uint buildingSize, undefined4 param_7, undefined4 height) + { + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, x, y, height, (BuildingType)(short)buildingType, buildingSize, playerID, (short)variation); + this->placedBuildingID = buildingID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, buildingSize); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (byte)height; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ccdcdde5b..e508e6bd8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42091,7 +42091,7 @@ SHC_3BB0A8C1_0x00506D40 | 89.6% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00506E10 | 0.0% | Pending -SHC_3BB0A8C1_0x00506F40 | 0.0% | Pending +SHC_3BB0A8C1_0x00506F40 | 85.2% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00507060 | 90.8% | setupBuildingData arg regalloc From b826c329b642660bbb079823ca70d4829b22b6c6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:55:46 +0200 Subject: [PATCH 123/252] reimplement: SHC_3BB0A8C1_0x00506E10 84.52% setupBuildingData arg regalloc --- .../Map/TileMapState/placeSiegeTent.cpp | 68 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeSiegeTent.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeSiegeTent.cpp b/src/OpenSHC/Map/TileMapState/placeSiegeTent.cpp new file mode 100644 index 000000000..fc3cb9cc3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeSiegeTent.cpp @@ -0,0 +1,68 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506E10 + void TileMapState::placeSiegeTent( + int playerID, uint x, uint y, undefined4 buildingType, uint buildingSize, int param_6, undefined4 height) + { + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, x, y, height, (BuildingType)(short)buildingType, buildingSize, playerID, param_6); + this->placedBuildingID = buildingID; + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, buildingSize); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if (buildingSizeTileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[buildingSizeTileIndex] = tile; + } + this->HeightLayer[tile] = (byte)height; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)buildingID; + buildingSizeTileIndex++; + this->BuildingWasLayer[tile] = (uchar)(short)buildingType; + this->ChangedLayer[tile] = 2; + } while (buildingSizeTileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e508e6bd8..395b984a3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42089,7 +42089,7 @@ SHC_3BB0A8C1_0x00506BD0 | 0.0% | Pending SHC_3BB0A8C1_0x00506D40 | 89.6% | setupBuildingData arg regalloc -SHC_3BB0A8C1_0x00506E10 | 0.0% | Pending +SHC_3BB0A8C1_0x00506E10 | 84.5% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00506F40 | 85.2% | setupBuildingData arg regalloc From 0427751e0d6d54ec2ad47fc4ec9ebbb50e61f438 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:55:46 +0200 Subject: [PATCH 124/252] reimplement: SHC_3BB0A8C1_0x00508DD0 43.08% extra callee-saved reg --- .../applyTreeBrushToLogicalLayer.cpp | 58 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/applyTreeBrushToLogicalLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/applyTreeBrushToLogicalLayer.cpp b/src/OpenSHC/Map/TileMapState/applyTreeBrushToLogicalLayer.cpp new file mode 100644 index 000000000..63ec0712f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/applyTreeBrushToLogicalLayer.cpp @@ -0,0 +1,58 @@ + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508DD0 + void TileMapState::applyTreeBrushToLogicalLayer(int treeID, int noVariation) + { + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[MACRO_CALL_MEMBER( + OpenSHC::Map::LandscapeState_Func::getValueFrom0UpTo3ForTreeTypeAndTreeStage, DAT_LandscapeState::ptr)( + DAT_LandscapeState::instance.trees[treeID].treeType, DAT_LandscapeState::instance.trees[treeID].stage)]; + uint baseY = DAT_LandscapeState::instance.trees[treeID].yPosition; + int baseTile = DAT_LandscapeState::instance.trees[treeID].xPosition + + DAT_ViewportRenderState::instance.translationMatrix[baseY].addXgetTile; + + int tile = baseTile; + uint y = baseY; + for (int tileIndex = 0; tileIndex < brushSize; tileIndex++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, tileIndex, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & L_BORDER) != 0) { + break; + } + if ((this->LogicLayer[tile] & (L_SEA | L_MARSH | L_MOAT)) == 0) { + if (noVariation == 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_TREE_VARIATION; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_TREE_VARIATION; + } + } + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(7, + DAT_LandscapeState::instance.trees[treeID].xPosition, DAT_LandscapeState::instance.trees[treeID].yPosition); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 395b984a3..dfebff536 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42763,7 +42763,7 @@ SHC_3BB0A8C1_0x00508DC2 | 0.0% | Pending SHC_3BB0A8C1_0x00508DC3 | 0.0% | Pending -SHC_3BB0A8C1_0x00508DD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00508DD0 | 43.1% | extra callee-saved reg SHC_3BB0A8C1_0x00508EC0 | 0.0% | Pending From f5ba42951ea421a5c65a9fa5d80e3b900e95b54b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 12:55:47 +0200 Subject: [PATCH 125/252] reimplement: SHC_3BB0A8C1_0x00515F40 69.86% Style pass, asm differs --- .../TileMapState/Constructor_TileMapState.cpp | 72 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/Constructor_TileMapState.cpp diff --git a/src/OpenSHC/Map/TileMapState/Constructor_TileMapState.cpp b/src/OpenSHC/Map/TileMapState/Constructor_TileMapState.cpp new file mode 100644 index 000000000..ce35f75e9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/Constructor_TileMapState.cpp @@ -0,0 +1,72 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00515F40 + TileMapState* TileMapState::Constructor_TileMapState() + { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupMovementDirectionTranslationMatrix, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupBuildingSizeIndexMapping, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupTileMapSections, this)(); + this->editorActiveBrush = 7; + this->refreshCertainTileMap = 2; + this->counter1 = 0; + this->mapperMax = FALSE; + this->unknownZero_0x5548fc = 0; + this->unknownZero_0x554904 = 0; + this->unknownZero_0x554900 = 0; + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_NULL; + this->refreshRelatedOne = 1; + this->field93_0x5548c8 = 0; + this->refreshRelatedTwo = 0; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + this->forceUpdateTextureTilemap = 1; + this->forceUpdateGFXLayers = 1; + this->refreshCertainTileMap_old = 4; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setChangedLayerToThreeAndMapping0x40x40, this)(); + this->moatTileCount = 0; + this->field122_0x554930 = 0; + this->field78_0x55488c = 0x50; + this->lastTime = timeGetTime(); + this->rockOrientation = 0; + this->field80_0x554894 = 0; + this->unknownTime_0x5549bc = timeGetTime(); + this->field161_0x5549c0 = 1; + this->temporaryTerrainTypeIndex = 0; + this->field188_0x554a14 = 0; + DAT_GameCore::instance.isTimeHalted = FALSE; + DAT_GameState::instance.mapAndTime.skirmishFogOfWar = 0; + this->ptr_LogicLayer = this->LogicLayer; + this->ptr_ChangedLayer = this->ChangedLayer; + this->ptr_TerrainTypeTileMap = this->Logic2Layer; + this->ptr_TerrainHeightTileMap = this->HeightLayer; + this->ptr_PathConnectionLayer = this->PathConnectionLayer; + this->ptr_OccupancyLayer = this->OccupancyLayer; + this->ptr_DamageLayer = this->DamageLayer; + this->ptr_MiscDisplayLayer = this->MiscDisplayLayer; + this->ptr_MovementDirectionTranslationMatrix = this; + this->ptr_SpecialAreasArray = this->specialAreasArray; + this->ptr_AIZoneLayer = this->AIZoneLayer; + this->currentMoatCount = 16000; + this->maxPitchDitchCount = 4000; + return this; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index dfebff536..7746972f8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44773,7 +44773,7 @@ SHC_3BB0A8C1_0x00515C80 | 52.6% | ecx not kept across callee SHC_3BB0A8C1_0x00515DA0 | 0.0% | Pending -SHC_3BB0A8C1_0x00515F40 | 0.0% | Pending +SHC_3BB0A8C1_0x00515F40 | 69.9% | Style pass, asm differs SHC_3BB0A8C1_0x005160C0 | 0.0% | Pending From 187bfb62564690ae352d6c8c56b263d6102beb02 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 14:24:20 +0200 Subject: [PATCH 126/252] reimplement: SHC_3BB0A8C1_0x00502390 28.09% brush loop regalloc --- src/OpenSHC/Map/TileMapState/setLand.cpp | 91 ++++++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setLand.cpp diff --git a/src/OpenSHC/Map/TileMapState/setLand.cpp b/src/OpenSHC/Map/TileMapState/setLand.cpp new file mode 100644 index 000000000..8b4a4bf34 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setLand.cpp @@ -0,0 +1,91 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_MEDIUM; + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CLIMBABLE; + using OpenSHC::Map::LogicHelpers::L_DEFAULT_EARTH_OR_TEXTURE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_DAIRY; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_HOP; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_WHEAT; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + related to setting oasis type decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00502390 + void TileMapState::setLand(int tile, uint y, uint brushType) + { + int baseTile = tile; + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[brushType]; + uint baseY = y; + int index = 0; + if (brushSize > 0) { + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0 + && (this->LogicLayer[tile] & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 + && this->BuildingLayer[tile] == 0 && (this->LogicLayer[tile] & L_TREE) == 0 + && ((this->LogicLayer[tile] & L_ROCKY) == 0 || this->OrganismLayer[tile] == 0)) { + if (this->DefaultHeightLayer[tile] < 8) { + this->DefaultHeightLayer[tile] = 8; + } + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffdf; + if ((this->LogicLayer[tile] & (L_MOAT | L_MOAT_DUG_OR_PLANNED)) != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .tileTranslationMatrix_YComponent[tile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_MOAT | L_MOAT_DUG_OR_PLANNED); + } + this->LogicLayer[tile] = this->LogicLayer[tile] + & (L_STOCKPILEUnk | L_PLAIN1_AND_FARM | L_BORDER | L_BORDER_EDGE | L_BUILDING + | L_MOAT_DUG_OR_PLANNED | L_DEFAULT_EARTH_OR_TEXTURE | L_UNKNOWN_WALL_RELATED | L_CLIMBABLE + | L_FARM_FIELD_WHEAT | L_FARM_FIELD_HOP | L_FARM_FIELD_APPLE | L_FARM_FIELD_DAIRY + | L_KEEP_NON_MANOR_HOUSE | L_MOAT); + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xf83f; + this->Logic2Layer[tile] = 0; + if (this->HeightLayer[tile] == 80) { + this->Logic2Layer[tile] = L2_PLATEAU_MEDIUM; + } else if (this->HeightLayer[tile] == 130) { + this->Logic2Layer[tile] = L2_PLATEAU_HIGH; + } + this->WallOwnerLayer[tile] = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + } + index++; + } while (index < brushSize); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7746972f8..b6747e31f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41571,7 +41571,7 @@ SHC_3BB0A8C1_0x00501FE0 | 0.0% | Pending SHC_3BB0A8C1_0x00502110 | 0.0% | Pending -SHC_3BB0A8C1_0x00502390 | 0.0% | Pending +SHC_3BB0A8C1_0x00502390 | 28.1% | brush loop regalloc SHC_3BB0A8C1_0x005024F0 | 0.0% | Pending From 6847ec90f47a43cc5bc978186070207043deae89 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 14:24:20 +0200 Subject: [PATCH 127/252] reimplement: SHC_3BB0A8C1_0x004F9220 88.06% owner store tail-merge --- .../Map/TileMapState/swapWallOwnership.cpp | 70 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/swapWallOwnership.cpp diff --git a/src/OpenSHC/Map/TileMapState/swapWallOwnership.cpp b/src/OpenSHC/Map/TileMapState/swapWallOwnership.cpp new file mode 100644 index 000000000..bb4afeb59 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/swapWallOwnership.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9220 + void TileMapState::swapWallOwnership(int playerID, int otherPlayerID) + { + for (int tile = 0; tile < 80400; tile += 6) { + if ((this->LogicLayer[tile + 0] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 0] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 0] = this->WallOwnerLayer[tile + 0] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 0] = this->WallOwnerLayer[tile + 0] & 0xf8 | (char)playerID - 1U; + } + } + if ((this->LogicLayer[tile + 1] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 1] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 1] = this->WallOwnerLayer[tile + 1] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 1] = this->WallOwnerLayer[tile + 1] & 0xf8 | (char)playerID - 1U; + } + } + if ((this->LogicLayer[tile + 2] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 2] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 2] = this->WallOwnerLayer[tile + 2] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 2] = this->WallOwnerLayer[tile + 2] & 0xf8 | (char)playerID - 1U; + } + } + if ((this->LogicLayer[tile + 3] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 3] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 3] = this->WallOwnerLayer[tile + 3] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 3] = this->WallOwnerLayer[tile + 3] & 0xf8 | (char)playerID - 1U; + } + } + if ((this->LogicLayer[tile + 4] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 4] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 4] = this->WallOwnerLayer[tile + 4] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 4] = this->WallOwnerLayer[tile + 4] & 0xf8 | (char)playerID - 1U; + } + } + if ((this->LogicLayer[tile + 5] & L_WALL_OR_GATEHOUSE) != 0) { + int owner = (this->WallOwnerLayer[tile + 5] & 7) + 1; + if (owner == playerID) { + this->WallOwnerLayer[tile + 5] = this->WallOwnerLayer[tile + 5] & 0xf8 | (char)otherPlayerID - 1U; + } else if (owner == otherPlayerID) { + this->WallOwnerLayer[tile + 5] = this->WallOwnerLayer[tile + 5] & 0xf8 | (char)playerID - 1U; + } + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b6747e31f..d8bb75bc3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39381,7 +39381,7 @@ SHC_3BB0A8C1_0x004F8BD0 | 0.0% | Pending SHC_3BB0A8C1_0x004F9000 | 0.0% | Pending -SHC_3BB0A8C1_0x004F9220 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9220 | 88.1% | owner store tail-merge SHC_3BB0A8C1_0x004F93E0 | 49.0% | const 1 rematerialised From 63fcb398de30a049e44752f07a66333be8543303 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 14:24:21 +0200 Subject: [PATCH 128/252] reimplement: SHC_3BB0A8C1_0x005110B0 84.02% moat scan regalloc --- .../Map/TileMapState/createMoatData.cpp | 71 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/createMoatData.cpp diff --git a/src/OpenSHC/Map/TileMapState/createMoatData.cpp b/src/OpenSHC/Map/TileMapState/createMoatData.cpp new file mode 100644 index 000000000..6f1a52f25 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/createMoatData.cpp @@ -0,0 +1,71 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Game::GameMode2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005110B0 + int TileMapState::createMoatData(undefined4 playerID, uint x, uint y, int filled) + { + if (x > 399 || y > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0; + } + + int existingMoatID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)( + DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x); + if (existingMoatID != 0) { + return existingMoatID; + } + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SIEGE_THAT + && MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::hasEnoughGoldForMoat, DAT_BuildingsState::ptr)() + == 0) { + return 0; + } + + for (int moatID = 1; moatID < 16000; moatID++) { + if (this->moats[moatID].owner != 0) { + continue; + } + + if (this->currentMoatCount <= moatID) { + this->currentMoatCount = moatID + 1; + } + this->moats[moatID].owner = (char)playerID; + this->moats[moatID].x = (short)x; + this->moats[moatID].y = (short)y; + this->moats[moatID].tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + this->moats[moatID].zeroOrTwo = 2; + if (filled == 0) { + this->moats[moatID].stage = 1; + this->moats[moatID].fillProgress = 0; + this->moatTileCount = this->moatTileCount + 1; + return moatID; + } + this->moats[moatID].stage = 2; + this->moats[moatID].fillProgress = 4; + this->moatTileCount = this->moatTileCount + 1; + return moatID; + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d8bb75bc3..e21931152 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44175,7 +44175,7 @@ SHC_3BB0A8C1_0x0051101C | 0.0% | Pending SHC_3BB0A8C1_0x00511020 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005110B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005110B0 | 84.0% | moat scan regalloc SHC_3BB0A8C1_0x005111D0 | 0.0% | Pending From fb733ff78116f957c7addb99069fb5b916294062 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 21:41:14 +0200 Subject: [PATCH 129/252] reimplement: SHC_3BB0A8C1_0x004FF990 74.55% switch arm regalloc --- .../Map/TileMapState/returnSomeHeight.cpp | 84 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/returnSomeHeight.cpp diff --git a/src/OpenSHC/Map/TileMapState/returnSomeHeight.cpp b/src/OpenSHC/Map/TileMapState/returnSomeHeight.cpp new file mode 100644 index 000000000..aaf72d2cb --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/returnSomeHeight.cpp @@ -0,0 +1,84 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FF990 + uint TileMapState::returnSomeHeight(int tile, int param_2) + { + int extraHeight = 0; + if ((this->LogicLayer[tile] & L_KEEP_NON_MANOR_HOUSE) != 0) { + return this->HeightLayer[tile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + + if ((this->LogicLayer[tile] & L_BUILDING) != 0) { + short buildingID = this->BuildingLayer[tile]; + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_TOWER: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + return this->HeightLayer[tile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(buildingID) + + 10; + case OpenSHC::Map::Buildings::BT_HUNTERSHUT: + if (param_2 != 0) { + return this->HeightLayer[tile]; + } + default: + return this->HeightLayer[tile] + + DAT_BuildingDefinedData::instance + .BuildingHeights[DAT_BuildingsState::instance.buildings[buildingID].buildingType]; + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + return this->HeightLayer[tile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(buildingID); + } + } + + /* + OrganismLayer holds tree ids below 2000 and rock ids biased by 2000; Ghidra rendered the + rock lookup as an out-of-bounds index into trees[0x636]. + */ + if ((this->LogicLayer[tile] & L_ROCKY) != 0 && (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0 + && this->OrganismLayer[tile] >= 2000) { + short rockType = DAT_LandscapeState::instance.rocks[this->OrganismLayer[tile] - 2000].type; + if (rockType >= 0xd) { + return this->HeightLayer[tile] + 0x46; + } + if (rockType >= 9) { + extraHeight = 0x32; + } + } + return this->HeightLayer[tile] + extraHeight; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e21931152..9dc0fd1ef 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41105,7 +41105,7 @@ SHC_3BB0A8C1_0x004FF420 | 0.0% | Pending SHC_3BB0A8C1_0x004FF870 | 74.7% | __asm macro; global not nameable -SHC_3BB0A8C1_0x004FF990 | 0.0% | Pending +SHC_3BB0A8C1_0x004FF990 | 74.5% | switch arm regalloc SHC_3BB0A8C1_0x004FFAAC | 0.0% | Pending From c11fce6a94f43d4ea15840e4a0687397a33a42eb Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 21:41:14 +0200 Subject: [PATCH 130/252] reimplement: SHC_3BB0A8C1_0x005116E0 72.43% pitch field reload/regalloc --- .../Map/TileMapState/placePitchDitch.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placePitchDitch.cpp diff --git a/src/OpenSHC/Map/TileMapState/placePitchDitch.cpp b/src/OpenSHC/Map/TileMapState/placePitchDitch.cpp new file mode 100644 index 000000000..09131e506 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placePitchDitch.cpp @@ -0,0 +1,74 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005116E0 + int TileMapState::placePitchDitch(undefined4 playerID, uint x, uint y) + { + if (x > 399 || y > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return 0; + } + + int existingPitchDitchID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getPitchDitchIDForTile, this)( + DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x); + if (existingPitchDitchID != 0) { + return existingPitchDitchID; + } + + for (int pitchDitchID = 1; pitchDitchID < 4000; pitchDitchID++) { + if (this->pitchDitches[pitchDitchID].owner != 0) { + continue; + } + + if (this->maxPitchDitchCount <= pitchDitchID) { + this->maxPitchDitchCount = pitchDitchID + 1; + } + this->pitchDitches[pitchDitchID].owner = (short)playerID; + this->pitchDitches[pitchDitchID].uid = DAT_GameCore::instance.uniqueGameObjectTracker; + DAT_GameCore::instance.uniqueGameObjectTracker = DAT_GameCore::instance.uniqueGameObjectTracker + 1; + this->pitchDitches[pitchDitchID].y = (short)y; + this->pitchDitches[pitchDitchID].x = (short)x; + this->pitchDitches[pitchDitchID].state = 0; + this->pitchDitches[pitchDitchID].field7_0x12 = 0; + this->pitchDitches[pitchDitchID].tile + = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + this->pitchDitches[pitchDitchID].rng = SEC_RNG::instance.currentNumber2; + if (this->HeightLayer[this->pitchDitches[pitchDitchID].tile] < 5) { + this->HeightLayer[this->pitchDitches[pitchDitchID].tile] = 0; + } else { + this->HeightLayer[this->pitchDitches[pitchDitchID].tile] + = this->HeightLayer[this->pitchDitches[pitchDitchID].tile] - 4; + } + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + this->LogicLayer[this->pitchDitches[pitchDitchID].tile] + = this->LogicLayer[this->pitchDitches[pitchDitchID].tile] | L_PLAIN2_AND_PITCH; + this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] + = this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] & 0xbfff; + this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] + = this->MiscDisplayLayer[this->pitchDitches[pitchDitchID].tile] & 0xdfff; + this->ChangedLayer[this->pitchDitches[pitchDitchID].tile] = 2; + return pitchDitchID; + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9dc0fd1ef..2359e1737 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44187,7 +44187,7 @@ SHC_3BB0A8C1_0x005114C0 | 0.0% | Pending SHC_3BB0A8C1_0x005115C0 | 0.0% | Pending -SHC_3BB0A8C1_0x005116E0 | 0.0% | Pending +SHC_3BB0A8C1_0x005116E0 | 72.4% | pitch field reload/regalloc SHC_3BB0A8C1_0x00511850 | 58.8% | ecx not kept across callee From 441a92bad442c39e594346cecea6a9c31d8a580d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:15:01 +0200 Subject: [PATCH 131/252] reimplement: SHC_3BB0A8C1_0x005127B0 100.00% Reimplemented --- .../resetAreaBasedOnLogicalLayer.cpp | 72 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetAreaBasedOnLogicalLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetAreaBasedOnLogicalLayer.cpp b/src/OpenSHC/Map/TileMapState/resetAreaBasedOnLogicalLayer.cpp new file mode 100644 index 000000000..f6a5a762a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetAreaBasedOnLogicalLayer.cpp @@ -0,0 +1,72 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005127B0 + void TileMapState::resetAreaBasedOnLogicalLayer() + { + for (int tile = 0; tile < 80400; tile++) { + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0) { + continue; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::useEraserBrush, this)(tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile], 1); + this->GfxLayer[tile] = 0; + this->AlphaGFXLayer[tile] = 0; + this->ConstructionGFXLayer[tile] = 0; + this->PillarGFXLayer[tile] = 1; + this->WallGFXLayer[tile] = 0; + this->FloatingLayer[tile] = 0; + this->UnitLayer[tile] = 0; + this->EntityLayer[tile] = 0; + this->EntityLayerLT25[tile] = 0; + this->BuildingLayer[tile] = 0; + this->LogicLayer[tile] = 0; + this->Logic2Layer[tile] = 0; + this->ChangedLayer[tile] = 0; + this->OrganismLayer[tile] = 0; + this->DamageLayer[tile] = 0; + this->MacroLayer[tile] = 0; + this->HeightLayer[tile] = 8; + this->DefaultHeightLayer[tile] = 8; + this->ShowHiLayer[tile] = 0; + this->MiscDisplayLayer[tile] = 0; + this->LuminesenceLayer[tile] = 0; + this->WallOwnerLayer[tile] = 0; + this->BuildingWasLayer[tile] = 0; + this->OccupancyLayer[tile] = 0; + this->AIZoneLayer[tile] = 0; + this->AIInfoLayer[tile] = 0; + this->unitDeathHeatMap[tile] = 0; + this->SEC_TileMap1104[tile] = 0; + this->SEC_PathfindingCostTileMap1105[0][tile] = 0; + this->SEC_PathfindingCostTileMap1105[1][tile] = 0; + this->SEC_PathfindingCostTileMap1105[2][tile] = 0; + this->SEC_PathfindingCostTileMap1105[3][tile] = 0; + this->SEC_PathfindingCostTileMap1105[4][tile] = 0; + this->SEC_PathfindingCostTileMap1105[5][tile] = 0; + this->SEC_PathfindingCostTileMap1105[6][tile] = 0; + this->SEC_PathfindingCostTileMap1105[7][tile] = 0; + this->SEC_PathfindingCostTileMap1105[8][tile] = 0; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2359e1737..da195e592 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44735,7 +44735,7 @@ SHC_3BB0A8C1_0x00512180 | 0.0% | Pending SHC_3BB0A8C1_0x00512450 | 0.0% | Pending -SHC_3BB0A8C1_0x005127B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005127B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005127D0 | 0.0% | Pending From b588ae8f3da885c66db17e7c239ec9012ee1d179 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:15:01 +0200 Subject: [PATCH 132/252] reimplement: SHC_3BB0A8C1_0x004FB770 76.65% gfx expression regalloc --- .../applyRockGraphicsToFootprint.cpp | 67 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/applyRockGraphicsToFootprint.cpp diff --git a/src/OpenSHC/Map/TileMapState/applyRockGraphicsToFootprint.cpp b/src/OpenSHC/Map/TileMapState/applyRockGraphicsToFootprint.cpp new file mode 100644 index 000000000..3a5769ea9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/applyRockGraphicsToFootprint.cpp @@ -0,0 +1,67 @@ + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB770 + void TileMapState::applyRockGraphicsToFootprint(int rockID) + { + short rockX = DAT_LandscapeState::instance.rocks[rockID].x; + short rockY = DAT_LandscapeState::instance.rocks[rockID].y; + int orientation = DAT_LandscapeState::instance.rocks[rockID].orientation + this->mapOrientation; + if (orientation > 7) { + orientation = orientation - 8; + } + short size = DAT_LandscapeState::instance.rocks[rockID].size; + short surface = (short)(orientation / 2) * size * size; + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + index, DAT_LandscapeState::instance.rocks[rockID].size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + rockY].addXgetTile + rockX + + this->buildingX; + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + if (this->field93_0x5548c8 == 0) { + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance[DAT_LandscapeState::instance.rocks[rockID] + .unknownGMID] + + (short)DAT_LandscapeState::instance.rocks[rockID].gfx + + (short)this->buildingRotationRelatedValue + surface) + - 1; + } else if (DAT_LandscapeState::instance.rocks[rockID].size == 1) { + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance[DAT_LandscapeState::instance.rocks[rockID] + .unknownGMID] + + (short)DAT_LandscapeState::instance.rocks[rockID].gfx + + (short)this->buildingRotationRelatedValue + surface) + - 1; + } else { + this->GfxLayer[tile] + = (short)MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::getRandomRockImageOffset, + DAT_LandscapeState::ptr)(((byte)this->RandomLayer[tile] & 3) + 1) + + (short) + GMTotalPicturesProcessed::instance[DAT_LandscapeState::instance.rocks[rockID].unknownGMID] + + surface - 1; + } + } + index++; + } while (index < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index da195e592..f256d0c6c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40571,7 +40571,7 @@ SHC_3BB0A8C1_0x004FB3F0 | 34.3% | XYPair stride regalloc SHC_3BB0A8C1_0x004FB4D0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FB770 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB770 | 76.7% | gfx expression regalloc SHC_3BB0A8C1_0x004FB7D0 | 0.0% | Pending From 9a322bba2324e48eccc261fb3b9c287c0bf2f8c3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:17:25 +0200 Subject: [PATCH 133/252] reimplement: SHC_3BB0A8C1_0x00506BD0 75.90% setupBuildingData arg regalloc --- .../Map/TileMapState/placeWorkshopOrHovel.cpp | 74 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeWorkshopOrHovel.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeWorkshopOrHovel.cpp b/src/OpenSHC/Map/TileMapState/placeWorkshopOrHovel.cpp new file mode 100644 index 000000000..796a39daa --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeWorkshopOrHovel.cpp @@ -0,0 +1,74 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506BD0 + void TileMapState::placeWorkshopOrHovel( + int playerID, uint x, uint y, BuildingType type, uint size, int orientation, undefined4 averageHeight) + { + int buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, x, y, averageHeight, (BuildingType)(short)type, size, playerID, orientation); + /* the original stores only the low half of the int field */ + *(short*)&DAT_BuildingsState::instance.buildings[buildingID].hovelVisualStyle + = (short)DAT_GameState::instance.playerDataArray[playerID].hovelCountUpToEight; + this->placedBuildingID = buildingID; + if (type == OpenSHC::Map::Buildings::BT_HOVEL) { + DAT_GameState::instance.playerDataArray[playerID].hovelCountUpToEight + = (DAT_GameState::instance.playerDataArray[playerID].hovelCountUpToEight + 1) % 7; + } + int tileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(tileIndex, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if (tileIndex < 36) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[tileIndex] = tile; + } + this->HeightLayer[tile] = (byte)averageHeight; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)buildingID; + tileIndex++; + this->BuildingWasLayer[tile] = (uchar)type; + this->ChangedLayer[tile] = 2; + } while (tileIndex < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < (int)DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f256d0c6c..78ed75e92 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42085,7 +42085,7 @@ SHC_3BB0A8C1_0x00506370 | 0.0% | Pending SHC_3BB0A8C1_0x00506AD0 | 0.0% | Pending -SHC_3BB0A8C1_0x00506BD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00506BD0 | 75.9% | setupBuildingData arg regalloc SHC_3BB0A8C1_0x00506D40 | 89.6% | setupBuildingData arg regalloc From 0a7bbd14bc87eb22f14386bdf33a977b56a4ac52 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:17:25 +0200 Subject: [PATCH 134/252] reimplement: SHC_3BB0A8C1_0x00500980 65.08% height compare regalloc --- .../findNearestValidDigTileNearTarget.cpp | 82 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/findNearestValidDigTileNearTarget.cpp diff --git a/src/OpenSHC/Map/TileMapState/findNearestValidDigTileNearTarget.cpp b/src/OpenSHC/Map/TileMapState/findNearestValidDigTileNearTarget.cpp new file mode 100644 index 000000000..9343e79cf --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/findNearestValidDigTileNearTarget.cpp @@ -0,0 +1,82 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00500980 + undefined4 TileMapState::findNearestValidDigTileNearTarget(uint x1, uint y1, uint x2, uint y2) + { + if (x1 > 399 || y1 > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y1 * 400 + x1] == 0) { + return 0; + } + if (x2 > 399 || y2 > 399) { + return 0; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y2 * 400 + x2] == 0) { + return 0; + } + + ushort area + = this->PathConnectionLayer[DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile + x1]; + int targetTile = DAT_ViewportRenderState::instance.translationMatrix[y2].addXgetTile + x2; + uint targetHeight = this->HeightLayer[targetTile]; + int bestDistance = 10000; + int bestIndex = -1; + if (this->BuildingLayer[targetTile] != 0) { + targetHeight = targetHeight + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(this->BuildingLayer[targetTile]); + } + + for (int index = 0; index < 4; index++) { + int fromXPosition = DAT_TerrainDefinedData::instance.field2478_0x378c[index].x + x2; + int fromYPosition = DAT_TerrainDefinedData::instance.field2478_0x378c[index].y + y2; + int tile = DAT_ViewportRenderState::instance.translationMatrix[fromYPosition].addXgetTile + fromXPosition; + if (this->PathConnectionLayer[tile] != area) { + continue; + } + uint height = this->HeightLayer[tile]; + if (this->BuildingLayer[tile] != 0) { + height = height + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + if ((int)height >= (int)(targetHeight + 0x10) || (int)(targetHeight - 0x10) >= (int)height) { + continue; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(x1, y1, fromXPosition, fromYPosition); + if (DAT_DirectionAlgorithmState::instance.distanceHigh < bestDistance) { + bestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + bestIndex = index; + } + } + + if (bestIndex >= 0) { + this->field155_0x5549a8 = DAT_TerrainDefinedData::instance.field2478_0x378c[bestIndex].x + x2; + this->field156_0x5549ac = DAT_TerrainDefinedData::instance.field2478_0x378c[bestIndex].y + y2; + return 1; + } + this->field155_0x5549a8 = x2; + this->field156_0x5549ac = y2; + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 78ed75e92..865e6b1d3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41465,7 +41465,7 @@ SHC_3BB0A8C1_0x00500890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00500940 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00500980 | 0.0% | Pending +SHC_3BB0A8C1_0x00500980 | 65.1% | height compare regalloc SHC_3BB0A8C1_0x00500B50 | 68.3% | loop guard/regalloc differs From baecfa33a28a148080db7057e35a9a1dd7138bea Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:24:11 +0200 Subject: [PATCH 135/252] reimplement: SHC_3BB0A8C1_0x004FFF10 44.03% switch arm regalloc --- ...etHeightAtTileIncludingOwnersBuildings.cpp | 93 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getHeightAtTileIncludingOwnersBuildings.cpp diff --git a/src/OpenSHC/Map/TileMapState/getHeightAtTileIncludingOwnersBuildings.cpp b/src/OpenSHC/Map/TileMapState/getHeightAtTileIncludingOwnersBuildings.cpp new file mode 100644 index 000000000..d7d7b417d --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getHeightAtTileIncludingOwnersBuildings.cpp @@ -0,0 +1,93 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FFF10 + uint TileMapState::getHeightAtTileIncludingOwnersBuildings(int tile, int playerID) + { + /* + The early layer reads go through the global instance's absolute address, while the + BuildingLayer reads inside the switch arms go through this; follow each one separately. + */ + if (DAT_TileMapState::instance.PathConnectionLayer[tile] == 0) { + return 0; + } + if ((DAT_TileMapState::instance.MiscDisplayLayer[tile] & 0x1000) != 0) { + return 0; + } + + if ((DAT_TileMapState::instance.LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0) { + if (playerID != 0 && (this->WallOwnerLayer[tile] & 7) + 1 != playerID) { + return 0; + } + return DAT_TileMapState::instance.HeightLayer[tile]; + } + + short buildingID = DAT_TileMapState::instance.BuildingLayer[tile]; + if (buildingID == 0) { + return 0; + } + if (playerID != 0 && DAT_BuildingsState::instance.buildings[buildingID].owner != playerID) { + return 0; + } + + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + for (int direction = 0; direction < 8; direction++) { + if (this->BuildingLayer[DAT_TileMapState::instance.directionTranslationMatrix[DAT_ViewportRenderState:: + instance.tileTranslationMatrix_YComponent[tile]][direction] + + tile] + != buildingID) { + return 0; + } + } + return MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, this)(tile); + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: { + int firstDirection = 0; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0x50) { + firstDirection = 2; + } + int secondDirection = firstDirection + 4; + if (this->BuildingLayer[DAT_TileMapState::instance.directionTranslationMatrix[DAT_ViewportRenderState:: + instance.tileTranslationMatrix_YComponent[tile]][firstDirection] + + tile] + != buildingID) { + return 0; + } + if (this->BuildingLayer[DAT_TileMapState::instance.directionTranslationMatrix[DAT_ViewportRenderState:: + instance.tileTranslationMatrix_YComponent[tile]][secondDirection] + + tile] + != buildingID) { + return 0; + } + return MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTotalHeightAtTile, this)(tile); + } + } + return 0; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 865e6b1d3..3e9d4ddb6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41349,7 +41349,7 @@ SHC_3BB0A8C1_0x004FFF01 | 0.0% | Pending SHC_3BB0A8C1_0x004FFF02 | 0.0% | Pending -SHC_3BB0A8C1_0x004FFF10 | 0.0% | Pending +SHC_3BB0A8C1_0x004FFF10 | 44.0% | switch arm regalloc SHC_3BB0A8C1_0x00500060 | 0.0% | Pending From e7670afa4f8adce58321803c1e4c8fa314a22a85 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:24:11 +0200 Subject: [PATCH 136/252] reimplement: SHC_3BB0A8C1_0x00506AD0 77.94% buildingType chain tail-merge --- .../updatePathLinkagesForBuilding.cpp | 81 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updatePathLinkagesForBuilding.cpp diff --git a/src/OpenSHC/Map/TileMapState/updatePathLinkagesForBuilding.cpp b/src/OpenSHC/Map/TileMapState/updatePathLinkagesForBuilding.cpp new file mode 100644 index 000000000..894fa4a1a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updatePathLinkagesForBuilding.cpp @@ -0,0 +1,81 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506AD0 + void TileMapState::updatePathLinkagesForBuilding(int buildingID) + { + int buildingSizeTileIndex = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + buildingSizeTileIndex, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight); + int y = DAT_BuildingsState::instance.buildings[buildingID].y + this->buildingY; + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + + DAT_BuildingsState::instance.buildings[buildingID].x + this->buildingX; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoat, this)(tile); + buildingSizeTileIndex++; + } while (buildingSizeTileIndex < this->constructionTileCount); + + short buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + if (buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToGates, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToGates, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_WOODGATE1) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToGates, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_STONEKEEP) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToKeeps, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_STRONGHOLD) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToKeeps, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_KEEPFOUR) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToKeeps, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_KEEPFIVE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToKeeps, + DAT_PathFindingState::ptr)(buildingID); + return; + } + if (buildingType == OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageTileMapRelatedToSiegeTower, + DAT_PathFindingState::ptr)(buildingID); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3e9d4ddb6..109a0816b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42083,7 +42083,7 @@ SHC_3BB0A8C1_0x005060C0 | 0.0% | Pending SHC_3BB0A8C1_0x00506370 | 0.0% | Pending -SHC_3BB0A8C1_0x00506AD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00506AD0 | 77.9% | buildingType chain tail-merge SHC_3BB0A8C1_0x00506BD0 | 75.9% | setupBuildingData arg regalloc From 545e832001db223b13f44bd4b11ae4855179afec Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 22:34:30 +0200 Subject: [PATCH 137/252] reimplement: SHC_3BB0A8C1_0x004F6B20 30.11% row counter costs a spill --- ...etupMovementDirectionTranslationMatrix.cpp | 80 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupMovementDirectionTranslationMatrix.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupMovementDirectionTranslationMatrix.cpp b/src/OpenSHC/Map/TileMapState/setupMovementDirectionTranslationMatrix.cpp new file mode 100644 index 000000000..f0383259f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupMovementDirectionTranslationMatrix.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6B20 + void TileMapState::setupMovementDirectionTranslationMatrix() + { + /* + Ghidra rendered the two running values of the first loop as directionTranslationMatrix[199][4] + and [200][5]; in the original they are registers, and rows 199 and 200 are only written by + the block after the loop. Rows 0..198 count up in "step" and down in "counter", rows 201.. count + back down again. + */ + int step = 2; + int counter = 0; + int row = 0; + do { + this->directionTranslationMatrix[row][0] = counter - 1; + this->directionTranslationMatrix[row][3] = step + 2; + this->directionTranslationMatrix[row][4] = step + 1; + this->directionTranslationMatrix[row][1] = counter; + this->directionTranslationMatrix[row][5] = step; + this->directionTranslationMatrix[row][2] = 1; + this->directionTranslationMatrix[row][6] = -1; + this->directionTranslationMatrix[row][7] = counter - 2; + this->yArray1[row] = step; + counter = counter - 2; + step = step + 2; + row++; + } while (counter > -398); + + this->directionTranslationMatrix[199][1] = 2 - step; + this->directionTranslationMatrix[199][4] = step; + this->directionTranslationMatrix[199][6] = -1; + this->directionTranslationMatrix[199][2] = 1; + this->directionTranslationMatrix[199][3] = step + 1; + this->directionTranslationMatrix[199][0] = 1 - step; + this->directionTranslationMatrix[199][7] = -step; + this->directionTranslationMatrix[199][5] = step - 1; + this->yArray1[199] = step; + this->directionTranslationMatrix[200][0] = -step; + this->directionTranslationMatrix[200][1] = 1 - step; + this->directionTranslationMatrix[200][2] = 1; + this->directionTranslationMatrix[200][3] = step; + this->directionTranslationMatrix[200][4] = step - 1; + this->directionTranslationMatrix[200][5] = step - 2; + this->directionTranslationMatrix[200][6] = -1; + this->directionTranslationMatrix[200][7] = -1 - step; + this->yArray1[200] = step; + + if (step - 2 > 0) { + int lowerStep = step - 2; + int lowerCounter = -2 - lowerStep; + int lowerRow = 201; + do { + this->directionTranslationMatrix[lowerRow][0] = lowerCounter + 1; + this->directionTranslationMatrix[lowerRow][1] = lowerCounter + 2; + this->directionTranslationMatrix[lowerRow][4] = lowerStep - 1; + this->directionTranslationMatrix[lowerRow][3] = lowerStep; + this->directionTranslationMatrix[lowerRow][7] = lowerCounter; + this->directionTranslationMatrix[lowerRow][2] = 1; + this->directionTranslationMatrix[lowerRow][5] = lowerStep - 2; + this->directionTranslationMatrix[lowerRow][6] = -1; + this->yArray1[lowerRow] = lowerStep; + lowerStep = lowerStep - 2; + lowerCounter = lowerCounter + 2; + lowerRow++; + } while (lowerStep > 0); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 109a0816b..670a848d6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38741,7 +38741,7 @@ SHC_3BB0A8C1_0x004F6A80 | 0.0% | Pending SHC_3BB0A8C1_0x004F6AE0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F6B20 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6B20 | 30.1% | row counter costs a spill SHC_3BB0A8C1_0x004F6C20 | 0.0% | Pending From 21ba9d2e6c187750a0836d997a370f881ed33c0d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:03:56 +0200 Subject: [PATCH 138/252] reimplement: SHC_3BB0A8C1_0x00515DA0 36.10% brush loop regalloc --- src/OpenSHC/Map/TileMapState/placeTree.cpp | 104 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeTree.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeTree.cpp b/src/OpenSHC/Map/TileMapState/placeTree.cpp new file mode 100644 index 000000000..a5f682917 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeTree.cpp @@ -0,0 +1,104 @@ + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00515DA0 + void TileMapState::placeTree(uint x, uint y, undefined4 treeType) + { + if (x > 399 || y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + + int stage = MACRO_CALL_MEMBER( + OpenSHC::Map::LandscapeState_Func::getValueFrom0UpTo3ForTreeTypeAndTreeStage, DAT_LandscapeState::ptr)( + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::mapUITreeTypeToLogicalTreeType, + DAT_LandscapeState::ptr)((short)treeType), + 3); + uint baseTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[stage]; + if ((this->LogicLayer[baseTile] + & (L_SEA | L_PLAIN1_AND_FARM | L_BORDER | L_BORDER_EDGE | L_ROCKY | L_WALL_OR_GATEHOUSE | L_BUILDING + | L_TREE_VARIATION | L_BOULDERS | L_PEBBLES | L_IRON | L_RIVER | L_FORD | L_KEEP_NON_MANOR_HOUSE + | L_MARSH | L_MOAT)) + != 0) { + return; + } + + uint tile = baseTile; + uint brushY = y; + int index = 0; + if (brushSize > 0) { + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, (int*)&tile, (int*)&brushY, baseTile, y); + if ((this->LogicLayer[tile] & L_BORDER) != 0) { + break; + } + if ((this->LogicLayer[tile] & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_RIVER | L_KEEP_NON_MANOR_HOUSE)) + != 0) { + return; + } + if ((this->LogicLayer[tile] & L_ROCKY) != 0) { + return; + } + if (this->OrganismLayer[tile] != 0) { + return; + } + index++; + } while (index < brushSize); + } + + int treeID = MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::createTree, DAT_LandscapeState::ptr)(x, y, + (TreeType)(short)MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::mapUITreeTypeToLogicalTreeType, + DAT_LandscapeState::ptr)((short)treeType), + stage, 0, 0, 3); + this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] + = this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] & ~L_ROCKY; + this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] + = this->LogicLayer[DAT_LandscapeState::instance.trees[treeID].tile] | L_TREE; + this->OrganismLayer[DAT_LandscapeState::instance.trees[treeID].tile] = (short)treeID; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::applyTreeBrushToLogicalLayer, this)(treeID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)( + DAT_LandscapeState::instance.trees[treeID].yPosition, DAT_LandscapeState::instance.trees[treeID].tile); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 670a848d6..8e3eb9dae 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44771,7 +44771,7 @@ SHC_3BB0A8C1_0x00515A20 | 0.0% | Pending SHC_3BB0A8C1_0x00515C80 | 52.6% | ecx not kept across callee -SHC_3BB0A8C1_0x00515DA0 | 0.0% | Pending +SHC_3BB0A8C1_0x00515DA0 | 36.1% | brush loop regalloc SHC_3BB0A8C1_0x00515F40 | 69.9% | Style pass, asm differs From 8cc2b0beea360f5ecedce111fcee2fe8037d4e8b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:03:57 +0200 Subject: [PATCH 139/252] reimplement: SHC_3BB0A8C1_0x00501F50 9.68% one fewer spilled local --- .../Map/TileMapState/createPlateau.cpp | 103 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/createPlateau.cpp diff --git a/src/OpenSHC/Map/TileMapState/createPlateau.cpp b/src/OpenSHC/Map/TileMapState/createPlateau.cpp new file mode 100644 index 000000000..486f4cd93 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/createPlateau.cpp @@ -0,0 +1,103 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501F50 + void TileMapState::createPlateau(int tile, uint the_y, int brush, int plateauHeightSetting) + { + int baseTile = tile; + uint baseY = the_y; + /* the original reuses the brush parameter to hold the size */ + brush = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + + byte maxHeightInBrush = 0; + int index = 0; + if (brush > 0) { + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, &tile, (int*)&the_y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0 + && maxHeightInBrush < this->HeightLayer[tile]) { + maxHeightInBrush = this->HeightLayer[tile]; + } + index++; + } while (index < brush); + } + + tile = baseTile; + the_y = baseY; + index = 0; + if (brush > 0) { + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, &tile, (int*)&the_y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0 + && (this->LogicLayer[tile] & (L_SEA | L_BUILDING | L_KEEP_NON_MANOR_HOUSE | L_MARSH | L_MOAT)) == 0 + && this->BuildingLayer[tile] == 0 + && (this->LogicLayer[tile] + & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_MOAT_DUG_OR_PLANNED | L_KEEP_NON_MANOR_HOUSE + | L_MOAT)) + == 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + if (plateauHeightSetting == 4) { + this->HeightLayer[tile] = 80; + } else if (plateauHeightSetting == 8) { + this->HeightLayer[tile] = 130; + } + this->DefaultHeightLayer[tile] = this->HeightLayer[tile]; + if ((this->LogicLayer[tile] & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] - 8; + } + this->Logic2Layer[tile] = (byte)plateauHeightSetting; + this->DAT_SomeTile = tile; + this->DAT_SomeY = the_y; + + /* mark this tile and its eight neighbours changed, through the layer pointers */ + byte* changed = (byte*)this->ptr_ChangedLayer + tile; + int* directionRow = (int*)this->ptr_MovementDirectionTranslationMatrix + the_y * 8; + changed[1] = 2; + changed[-1] = 2; + changed[0] = 2; + byte* northRow = changed + directionRow[0]; + northRow[-1] = 2; + northRow[1] = 2; + northRow[0] = 2; + changed = changed + directionRow[4]; + changed[-1] = 2; + changed[1] = 2; + changed[0] = 2; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(the_y, tile); + } + index++; + } while (index < brush); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8e3eb9dae..27f380cc1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41565,7 +41565,7 @@ SHC_3BB0A8C1_0x00501CD0 | 82.0% | brush loop regalloc SHC_3BB0A8C1_0x00501D90 | 0.0% | Pending -SHC_3BB0A8C1_0x00501F50 | 0.0% | Pending +SHC_3BB0A8C1_0x00501F50 | 9.7% | one fewer spilled local SHC_3BB0A8C1_0x00501FE0 | 0.0% | Pending From 446ba2c8b4d5c1532e616ccac8bd255b0186df66 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:29:02 +0200 Subject: [PATCH 140/252] reimplement: SHC_3BB0A8C1_0x00501D90 15.18% spills where original uses reg --- src/OpenSHC/Map/TileMapState/raiseLand.cpp | 99 ++++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/raiseLand.cpp diff --git a/src/OpenSHC/Map/TileMapState/raiseLand.cpp b/src/OpenSHC/Map/TileMapState/raiseLand.cpp new file mode 100644 index 000000000..65aa53bc5 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/raiseLand.cpp @@ -0,0 +1,99 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501D90 + void TileMapState::raiseLand(int tile, uint y, uint brush, int change) + { + int baseTile = tile; + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + int index = 0; + /* the original reuses the brush parameter to hold the base y */ + brush = y; + if (brushSize < 1) { + this->forceUpdateTextureTilemap = 1; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + return; + } + + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 1, index, &tile, (int*)&y, baseTile, brush); + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BORDER | L_BORDER_EDGE)) == 0 + && ((logic & (L_SEA | L_MARSH)) == 0 || this->unknownZero_0x554904 != 0) + && ((logic & (L_SEA | L_MARSH)) != 0 || this->unknownZero_0x554904 != 1) + && (logic + & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_MOAT_DUG_OR_PLANNED | L_KEEP_NON_MANOR_HOUSE | L_MOAT)) + == 0 + && this->BuildingLayer[tile] == 0) { + byte minHeight; + byte maxHeight; + if ((logic & L_SEA) != 0) { + minHeight = 0; + maxHeight = 0; + } else if ((logic & (L_SEA | L_MARSH | L_MOAT)) == 0) { + minHeight = 8; + maxHeight = 128; + } else { + minHeight = 0; + maxHeight = 20; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + if ((this->LogicLayer[tile] & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] + 8; + } + this->ChangedLayer[tile] = 2; + if (this->HeightLayer[tile] <= minHeight) { + this->HeightLayer[tile] = minHeight; + } + if (this->HeightLayer[tile] != 0 || change >= 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] + (char)change; + this->Logic2Layer[tile] = 0; + } + if (this->HeightLayer[tile] < minHeight) { + this->HeightLayer[tile] = minHeight; + } + if (this->HeightLayer[tile] > maxHeight) { + this->HeightLayer[tile] = maxHeight; + } + this->DefaultHeightLayer[tile] = this->HeightLayer[tile]; + if ((this->LogicLayer[tile] & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] - 8; + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + } + index++; + } while (index < brushSize); + this->forceUpdateTextureTilemap = 1; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 27f380cc1..b9e76f476 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41563,7 +41563,7 @@ SHC_3BB0A8C1_0x00501CC8 | 0.0% | Pending SHC_3BB0A8C1_0x00501CD0 | 82.0% | brush loop regalloc -SHC_3BB0A8C1_0x00501D90 | 0.0% | Pending +SHC_3BB0A8C1_0x00501D90 | 15.2% | spills where original uses reg SHC_3BB0A8C1_0x00501F50 | 9.7% | one fewer spilled local From df332da6d0086f6850441c7f5bd7b5b543c13924 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:29:02 +0200 Subject: [PATCH 141/252] reimplement: SHC_3BB0A8C1_0x004FC810 67.21% height compare regalloc --- .../TileMapState/computeClimbRampRotation.cpp | 96 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/computeClimbRampRotation.cpp diff --git a/src/OpenSHC/Map/TileMapState/computeClimbRampRotation.cpp b/src/OpenSHC/Map/TileMapState/computeClimbRampRotation.cpp new file mode 100644 index 000000000..c7dd32baa --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/computeClimbRampRotation.cpp @@ -0,0 +1,96 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC810 + int TileMapState::computeClimbRampRotation(int tile, uint x, uint y) + { + uint height; + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + height = this->HeightLayer[tile]; + } else { + height = this->DefaultHeightLayer[tile]; + } + + int neighbour = this->directionTranslationMatrix[y][this->field86_0x5548ac] + tile; + uint heightAt86; + if ((this->LogicLayer[neighbour] & L_WALL_OR_GATEHOUSE) == 0) { + heightAt86 = this->HeightLayer[neighbour]; + } else { + heightAt86 = this->DefaultHeightLayer[neighbour]; + } + + neighbour = this->directionTranslationMatrix[y][this->field85_0x5548a8] + tile; + uint heightAt85; + if ((this->LogicLayer[neighbour] & L_WALL_OR_GATEHOUSE) == 0) { + heightAt85 = this->HeightLayer[neighbour]; + } else { + heightAt85 = this->DefaultHeightLayer[neighbour]; + } + + neighbour = this->directionTranslationMatrix[y][this->field84_0x5548a4] + tile; + uint heightAt84; + if ((this->LogicLayer[neighbour] & L_WALL_OR_GATEHOUSE) == 0) { + heightAt84 = this->HeightLayer[neighbour]; + } else { + heightAt84 = this->DefaultHeightLayer[neighbour]; + } + + uint rotation; + if (heightAt86 + 0x14 < height && heightAt86 < 0x88) { + if (heightAt85 + 0x14 < height && heightAt85 < 0x88) { + if (heightAt84 + 0x14 < height && heightAt84 < 0x88) { + rotation = 5; + } else { + rotation = 3; + } + } else { + rotation = 1; + } + } else if (heightAt85 + 0x14 < height && heightAt85 < 0x88) { + if (heightAt86 + 0x14 < height && heightAt86 < 0x88) { + rotation = 3; + } else { + rotation = 2; + } + } else if (heightAt86 < 0x88 || heightAt85 < 0x88) { + /* 0 when the tile is not high enough above its neighbour, 5 when it is */ + rotation = (uint)(height <= heightAt84 + 0x14) - 1 & 5; + } else { + rotation = 4; + } + + if (this->mapOrientation == 0) { + if (rotation == 1) { + this->field112_0x554908 = 0x20 - (x & 0x1f); + } else { + this->field112_0x554908 = 0x20 - (y & 0x1f); + } + } else if (this->mapOrientation == 4) { + if (rotation == 1) { + this->field112_0x554908 = (x & 0x1f) + 1; + } else { + this->field112_0x554908 = (y & 0x1f) + 1; + } + } else if (this->mapOrientation == 2) { + this->field112_0x554908 = (y & 0x1f) + 1; + } else { + this->field112_0x554908 = 0x20 - (y & 0x1f); + } + if (this->field112_0x554908 > 0x1f) { + this->field112_0x554908 = 1; + } + return rotation; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b9e76f476..20fe6e8cc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41093,7 +41093,7 @@ SHC_3BB0A8C1_0x004FC650 | 0.0% | Pending SHC_3BB0A8C1_0x004FC7C0 | 79.0% | setg vs sbb/neg -SHC_3BB0A8C1_0x004FC810 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC810 | 67.2% | height compare regalloc SHC_3BB0A8C1_0x004FC9E0 | 64.5% | Od stack slot order differs From 7264213f81d6e837fe5739c4481c866b23695aac Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:35:36 +0200 Subject: [PATCH 142/252] reimplement: SHC_3BB0A8C1_0x004FC650 45.52% orientation chain regalloc --- .../computeWallCornerRenderRotation.cpp | 93 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/computeWallCornerRenderRotation.cpp diff --git a/src/OpenSHC/Map/TileMapState/computeWallCornerRenderRotation.cpp b/src/OpenSHC/Map/TileMapState/computeWallCornerRenderRotation.cpp new file mode 100644 index 000000000..af521d95f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/computeWallCornerRenderRotation.cpp @@ -0,0 +1,93 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC650 + int TileMapState::computeWallCornerRenderRotation(uint x) + { + int tile = this->DAT_SomeTile; + int y = this->DAT_SomeY; + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isWallConnectionHeightValid, this)( + this->DAT_SomeTile, this->DAT_SomeY, 2) + != FALSE) { + if (this->mapOrientation == 0) { + if ((x & 0xf) != 0xf) { + return 17 - (x & 0xf); + } + return 2; + } + if (this->mapOrientation == 4) { + if ((x & 0xf) != 0) { + return (x & 0xf) + 2; + } + return 2; + } + if (this->mapOrientation == 2) { + if ((x & 0xf) == 0) { + return 1; + } + return (x & 0xf) + 0x11; + } + if (this->mapOrientation != 6) { + return 0; + } + if ((x & 0xf) == 0xf) { + return 1; + } + return 32 - (x & 0xf); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isWallConnectionHeightValid, this)(tile, y, 0) + != FALSE) { + if (this->mapOrientation == 0) { + if ((y & 0xf) != 0xf) { + return 32 - (y & 0xf); + } + return 1; + } + if (this->mapOrientation == 4) { + if ((y & 0xf) != 0) { + return (y & 0xf) + 0x11; + } + return 1; + } + if (this->mapOrientation == 6) { + if ((y & 0xf) == 0) { + return 2; + } + return (y & 0xf) + 2; + } + if (this->mapOrientation != 2) { + return 0; + } + if ((y & 0xf) == 0xf) { + return 2; + } + return 0x11 - (y & 0xf); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getWallFlagForOrientedDirection, this)(tile, y, 2) + != 0) { + return 48; + } + /* 0x3f when the other direction carries a wall too, 0x21 when it does not */ + return (-(uint)(MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getWallFlagForOrientedDirection, this)( + tile, y, 4) + != 0) + & 0x1e) + + 0x21; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 20fe6e8cc..b0010a985 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41089,7 +41089,7 @@ SHC_3BB0A8C1_0x004FC340 | 62.4% | LogicLayer walk regalloc SHC_3BB0A8C1_0x004FC490 | 0.0% | Pending -SHC_3BB0A8C1_0x004FC650 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC650 | 45.5% | orientation chain regalloc SHC_3BB0A8C1_0x004FC7C0 | 79.0% | setg vs sbb/neg From 9162f3a961297ace2dfc2690b4a4faa3165a9bc5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:35:36 +0200 Subject: [PATCH 143/252] reimplement: SHC_3BB0A8C1_0x004F9000 59.49% owner store tail-merge --- .../reassignWallOwnershipForPlayer.cpp | 90 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/reassignWallOwnershipForPlayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/reassignWallOwnershipForPlayer.cpp b/src/OpenSHC/Map/TileMapState/reassignWallOwnershipForPlayer.cpp new file mode 100644 index 000000000..7a7970207 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/reassignWallOwnershipForPlayer.cpp @@ -0,0 +1,90 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9000 + void TileMapState::reassignWallOwnershipForPlayer(int playerID, int newOwner) + { + for (int tile = 0; tile < 80400; tile += 6) { + if ((this->LogicLayer[tile + 0] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 0] == 0) { + matches = (this->WallOwnerLayer[tile + 0] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 0]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 0] = this->WallOwnerLayer[tile + 0] & 0xf8 | (char)newOwner - 1U; + } + } + if ((this->LogicLayer[tile + 1] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 1] == 0) { + matches = (this->WallOwnerLayer[tile + 1] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 1]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 1] = this->WallOwnerLayer[tile + 1] & 0xf8 | (char)newOwner - 1U; + } + } + if ((this->LogicLayer[tile + 2] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 2] == 0) { + matches = (this->WallOwnerLayer[tile + 2] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 2]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 2] = this->WallOwnerLayer[tile + 2] & 0xf8 | (char)newOwner - 1U; + } + } + if ((this->LogicLayer[tile + 3] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 3] == 0) { + matches = (this->WallOwnerLayer[tile + 3] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 3]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 3] = this->WallOwnerLayer[tile + 3] & 0xf8 | (char)newOwner - 1U; + } + } + if ((this->LogicLayer[tile + 4] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 4] == 0) { + matches = (this->WallOwnerLayer[tile + 4] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 4]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 4] = this->WallOwnerLayer[tile + 4] & 0xf8 | (char)newOwner - 1U; + } + } + if ((this->LogicLayer[tile + 5] & L_WALL_OR_GATEHOUSE) != 0) { + bool matches; + if (this->BuildingLayer[tile + 5] == 0) { + matches = (this->WallOwnerLayer[tile + 5] & 7) + 1 == playerID; + } else { + matches = DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile + 5]].owner == newOwner; + } + if (matches) { + this->WallOwnerLayer[tile + 5] = this->WallOwnerLayer[tile + 5] & 0xf8 | (char)newOwner - 1U; + } + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b0010a985..cd31793ef 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39379,7 +39379,7 @@ SHC_3BB0A8C1_0x004F8B50 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F8BD0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F9000 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9000 | 59.5% | owner store tail-merge SHC_3BB0A8C1_0x004F9220 | 88.1% | owner store tail-merge From adcff1ada6896303ea0be9eb348c945341d0289f Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:37:54 +0200 Subject: [PATCH 144/252] reimplement: SHC_3BB0A8C1_0x004F8300 80.29% mapper switch jump table --- .../rotateFearFactorBuildingVariations.cpp | 99 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/rotateFearFactorBuildingVariations.cpp diff --git a/src/OpenSHC/Map/TileMapState/rotateFearFactorBuildingVariations.cpp b/src/OpenSHC/Map/TileMapState/rotateFearFactorBuildingVariations.cpp new file mode 100644 index 000000000..6c83aa47c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/rotateFearFactorBuildingVariations.cpp @@ -0,0 +1,99 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8300 + void TileMapState::rotateFearFactorBuildingVariations() + { + /* + currentMapperCommand is reached through the global instance's absolute address, and the + switch below is the original's byte table at 0x004F847C into the jump table at 0x004F8454, + biased by M_MAPPER_GARDEN1. The "- 1 & 6" forms are the original's setcc/dec/and idiom. + */ + DWORD now = timeGetTime(); + if (this->field80_0x554894 == 5) { + if (this->rockOrientation == 0) { + this->rockOrientation = 2; + } else if (this->rockOrientation == 2) { + this->rockOrientation = 4; + } else { + this->rockOrientation = (this->rockOrientation != 4) - 1 & 6; + } + } + if ((int)(this->lastTime + 1000) > (int)now) { + return; + } + + this->lastTime = now; + this->field78_0x55488c = (this->field78_0x55488c == 0x50) + 0x50; + if (this->field80_0x554894 == 0) { + if (this->rockOrientation == 0) { + this->rockOrientation = 2; + } else if (this->rockOrientation == 2) { + this->rockOrientation = 4; + } else { + this->rockOrientation = (this->rockOrientation != 4) - 1 & 6; + } + } + + switch (this->currentMapperCommand) { + case OpenSHC::Commands::M_MAPPER_GARDEN1: + case OpenSHC::Commands::M_MAPPER_GARDEN2: + case OpenSHC::Commands::M_MAPPER_GARDEN3: + case OpenSHC::Commands::M_MAPPER_GARDEN4: + case OpenSHC::Commands::M_MAPPER_GARDEN5: + case OpenSHC::Commands::M_MAPPER_GARDEN7: + case OpenSHC::Commands::M_MAPPER_GARDEN8: + case OpenSHC::Commands::M_MAPPER_GARDEN10: + case OpenSHC::Commands::M_MAPPER_GARDEN11: + case OpenSHC::Commands::M_MAPPER_CESS_PIT1: + case OpenSHC::Commands::M_MAPPER_CESS_PIT2: + case OpenSHC::Commands::M_MAPPER_CESS_PIT3: + case OpenSHC::Commands::M_MAPPER_STATUE1: + case OpenSHC::Commands::M_MAPPER_STATUE2: + case OpenSHC::Commands::M_MAPPER_STATUE3: + case OpenSHC::Commands::M_MAPPER_STATUE4: + case OpenSHC::Commands::M_MAPPER_SHRINE1: + case OpenSHC::Commands::M_MAPPER_POND1: + case OpenSHC::Commands::M_MAPPER_POND3_LARGE1: + this->currentMapperCommand = (MappersEnum)(this->currentMapperCommand + OpenSHC::Commands::M_MAPPER_AREA); + return; + case OpenSHC::Commands::M_MAPPER_GARDEN6: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_GARDEN1; + return; + case OpenSHC::Commands::M_MAPPER_GARDEN9: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_GARDEN7; + return; + case OpenSHC::Commands::M_MAPPER_GARDEN12: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_GARDEN10; + return; + case OpenSHC::Commands::M_MAPPER_STATUE5: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_STATUE1; + return; + case OpenSHC::Commands::M_MAPPER_POND2_SMALL: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_POND1; + return; + case OpenSHC::Commands::M_MAPPER_POND4_LARGE2: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_POND3_LARGE1; + return; + case OpenSHC::Commands::M_MAPPER_SHRINE2: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_SHRINE1; + return; + case OpenSHC::Commands::M_MAPPER_CESS_PIT4: + this->currentMapperCommand = OpenSHC::Commands::M_MAPPER_CESS_PIT1; + return; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index cd31793ef..d22430d72 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38995,7 +38995,7 @@ SHC_3BB0A8C1_0x004F82F0 | 0.0% | Pending SHC_3BB0A8C1_0x004F82F1 | 0.0% | Pending -SHC_3BB0A8C1_0x004F8300 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8300 | 80.3% | mapper switch jump table SHC_3BB0A8C1_0x004F8454 | 0.0% | Pending From c64b420ed7e4d004371f4e86e283c70359c8eff7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:47:54 +0200 Subject: [PATCH 145/252] reimplement: SHC_3BB0A8C1_0x00511DF0 100.00% Reimplemented --- .../Map/TileMapState/setupTileMapSections.cpp | 60 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupTileMapSections.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupTileMapSections.cpp b/src/OpenSHC/Map/TileMapState/setupTileMapSections.cpp new file mode 100644 index 000000000..eb3b1f4f6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupTileMapSections.cpp @@ -0,0 +1,60 @@ + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00511DF0 + void TileMapState::setupTileMapSections() + { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->GfxLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->AlphaGFXLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->ConstructionGFXLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->PillarGFXLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->WallGFXLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->FloatingLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->UnitLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->EntityLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->EntityLayerLT25); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->BuildingLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x4e840, '\0', this->LogicLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->Logic2Layer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->ChangedLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->OrganismLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->DamageLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->MacroLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->HeightLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->DefaultHeightLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->ShowHiLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->MiscDisplayLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->LuminesenceLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->WallOwnerLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->BuildingWasLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->OccupancyLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->AIZoneLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->AIInfoLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->unitDeathHeatMap); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x13a10, '\0', this->SEC_TileMap1104); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0xb0a90, '\0', this->SEC_PathfindingCostTileMap1105); + + for (int tile = 0; tile < 80400; tile++) { + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + this->RandomLayer[tile] = SEC_RNG::instance.currentNumber2; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::changeMapOrientation, this)(0); + this->DAT_FutureMapOrientation = 8; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d22430d72..928866a51 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44725,7 +44725,7 @@ SHC_3BB0A8C1_0x00511D64 | 0.0% | Pending SHC_3BB0A8C1_0x00511D70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00511DF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00511DF0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005120C0 | 0.0% | Pending From b0d1b80009515e45af81debf8695204fbed9ace6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:47:55 +0200 Subject: [PATCH 146/252] reimplement: SHC_3BB0A8C1_0x00508030 61.13% 68.42% x/y param reuse regallo --- .../Map/TileMapState/placeOilsmelter.cpp | 89 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeOilsmelter.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeOilsmelter.cpp b/src/OpenSHC/Map/TileMapState/placeOilsmelter.cpp new file mode 100644 index 000000000..f22de7a1e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeOilsmelter.cpp @@ -0,0 +1,89 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508030 + void TileMapState::placeOilsmelter(int playerID, uint x, uint y, undefined4 height, uint sizeIndex, + int buildingTypeLike, undefined4 param_7) + { + int uid = DAT_GameCore::instance.uniqueGameObjectTracker; + + if (buildingTypeLike == 0xf) { + buildingTypeLike = 0; + } else { + buildingTypeLike = buildingTypeLike / 2; + } + + /* the id is kept zero-extended for the layer stores and sign-extended for the array index */ + ushort smelterID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, x, y, + param_7, (BuildingType)(int)(short)height, sizeIndex, playerID, 0xf); + int buildingID = (short)smelterID; + this->placedBuildingID = buildingID; + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = uid; + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, sizeIndex); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + this->HeightLayer[tile] = (byte)param_7; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = smelterID; + index++; + this->BuildingWasLayer[tile] = (uchar)height; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + + /* the campfire sits at a fixed offset from the smelter, chosen by the smelter's size */ + x = x + DAT_TerrainDefinedData::instance.field63_0x19c[buildingTypeLike].x; + y = y + DAT_TerrainDefinedData::instance.field63_0x19c[buildingTypeLike].y; + ushort campfire = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, x, y, + param_7, OpenSHC::Map::Buildings::BT_CAMPFIRE, 4, playerID, 0xf); + int campfireID = (short)campfire; + DAT_BuildingsState::instance.buildings[campfireID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[campfireID].quarryStockpileID = (short)this->placedBuildingID; + DAT_BuildingsState::instance.buildings[buildingID].quarryStockpileID = smelterID; + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + index, DAT_BuildingsState::instance.buildings[campfireID].widthOrHeight); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(tile); + this->HeightLayer[tile] = (byte)param_7; + this->BuildingLayer[tile] = campfire; + index++; + this->BuildingWasLayer[tile] = (uchar)height; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setTileRefsForOilSmelter, DAT_BuildingsState::ptr)(campfireID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(campfireID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(campfireID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, x, y); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 928866a51..5552ef5de 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42151,7 +42151,7 @@ SHC_3BB0A8C1_0x00507E00 | 0.0% | Pending SHC_3BB0A8C1_0x00507F80 | 0.0% | Pending -SHC_3BB0A8C1_0x00508030 | 0.0% | Pending +SHC_3BB0A8C1_0x00508030 | 61.1% | 68.42% x/y param reuse regallo SHC_3BB0A8C1_0x00508250 | 0.0% | Pending From 70fee826dd250d759a5cd9150421872cd68652c6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:47:55 +0200 Subject: [PATCH 147/252] reimplement: SHC_3BB0A8C1_0x005114C0 43.66% 46.51% global instance base re --- .../Map/TileMapState/updatePitchDitches.cpp | 82 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updatePitchDitches.cpp diff --git a/src/OpenSHC/Map/TileMapState/updatePitchDitches.cpp b/src/OpenSHC/Map/TileMapState/updatePitchDitches.cpp new file mode 100644 index 000000000..8aa4f6648 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updatePitchDitches.cpp @@ -0,0 +1,82 @@ + +#include "OpenSHC/Map/Entities.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005114C0 + void TileMapState::updatePitchDitches() + { + if (DAT_GameState::instance.gameTicksLoadBalancer % 10 == 3) { + this->maxPitchDitchCount = 0; + for (int id = 1; id < 4000; id++) { + if (this->pitchDitches[id].owner != 0) { + this->maxPitchDitchCount = id + 1; + } + } + } + + for (int id = 1; id < this->maxPitchDitchCount; id++) { + if (this->pitchDitches[id].owner == 0) { + continue; + } + int tile = this->pitchDitches[id].tile; + if ((this->LogicLayer[tile] & L_PLAIN2_AND_PITCH) == 0 || this->pitchDitches[id].state == -1) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::destroyPitchDitch, this)(id); + } else if (this->pitchDitches[id].state == 0) { + /* the original increments the state rather than storing the literal */ + this->pitchDitches[id].state = this->pitchDitches[id].state + 1; + this->pitchDitches[id].field7_0x12 = 0; + } else if (this->pitchDitches[id].state == 2) { + this->pitchDitches[id].field7_0x12 = this->pitchDitches[id].field7_0x12 + 1; + if (this->pitchDitches[id].field7_0x12 == 0x14) { + this->pitchDitches[id].state = this->pitchDitches[id].state + 1; + this->pitchDitches[id].field7_0x12 = 0; + uint height = this->HeightLayer[tile]; + /* the fire spreads to the four adjacent ditches that are still unlit */ + for (int i = 0; i < 4; i++) { + int neighbour = DAT_ViewportRenderState::instance + .translationMatrix[this->pitchDitches[id].y + + DAT_TerrainDefinedData::instance.field2477_0x376c[i].y] + .addXgetTile + + this->pitchDitches[id].x + DAT_TerrainDefinedData::instance.field2477_0x376c[i].x; + if ((this->LogicLayer[neighbour] & L_PLAIN2_AND_PITCH) == 0) { + continue; + } + int other = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getPitchDitchIDForTile, this)(neighbour); + if (other == 0 || this->pitchDitches[other].state != 1) { + continue; + } + if (abs((int)(height - this->HeightLayer[neighbour])) < 0x19) { + MACRO_CALL(OpenSHC::Map::Entities_Func::SetPlaceOnFire)(this->pitchDitches[other].owner, + this->pitchDitches[other].x * 8, this->pitchDitches[other].y * 8, + this->HeightLayer[this->pitchDitches[other].tile], 3); + this->pitchDitches[other].state = 2; + } + } + } + } else if (this->pitchDitches[id].state == 3) { + this->pitchDitches[id].field7_0x12 = this->pitchDitches[id].field7_0x12 + 1; + if (this->pitchDitches[id].field7_0x12 == 200) { + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->pitchDitches[id].state = -1; + } + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5552ef5de..2bf3b9ae5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44183,7 +44183,7 @@ SHC_3BB0A8C1_0x00511240 | 0.0% | Pending SHC_3BB0A8C1_0x005113F0 | 54.2% | moat field reload/regalloc -SHC_3BB0A8C1_0x005114C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005114C0 | 43.7% | 46.51% global instance base re SHC_3BB0A8C1_0x005115C0 | 0.0% | Pending From 9892baa9933007881117635d58ac1bb5c137104f Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:47:55 +0200 Subject: [PATCH 148/252] reimplement: SHC_3BB0A8C1_0x004FA460 100.00% Reimplemented --- .../getRubbleGraphicStageForDamageLevel.cpp | 79 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getRubbleGraphicStageForDamageLevel.cpp diff --git a/src/OpenSHC/Map/TileMapState/getRubbleGraphicStageForDamageLevel.cpp b/src/OpenSHC/Map/TileMapState/getRubbleGraphicStageForDamageLevel.cpp new file mode 100644 index 000000000..f51fe7e8e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getRubbleGraphicStageForDamageLevel.cpp @@ -0,0 +1,79 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA460 + undefined4 TileMapState::getRubbleGraphicStageForDamageLevel(int rotation) + { + /* the result lives in eax from the start (xor eax, eax), every comparison goes through ecx */ + int result = 0; + int orientation = this->mapOrientation; + if (orientation == 0) { + if (rotation == 0x50) { + result = 1; + } else if (rotation == 0x51) { + result = 0; + } else if (rotation == 1) { + result = 2; + } else if (rotation == 7) { + result = 5; + } else if (rotation == 3) { + result = 3; + } else if (rotation == 5) { + result = 4; + } + } else if (orientation == 4) { + if (rotation == 0x50) { + result = 1; + } else if (rotation == 0x51) { + result = 0; + } else if (rotation == 1) { + result = 4; + } else if (rotation == 7) { + result = 3; + } else if (rotation == 3) { + result = 5; + } else if (rotation == 5) { + result = 2; + } + } else if (orientation == 2) { + if (rotation == 0x50) { + result = 0; + } else if (rotation == 0x51) { + result = 1; + } else if (rotation == 1) { + result = 5; + } else if (rotation == 7) { + result = 4; + } else if (rotation == 3) { + result = 2; + } else if (rotation == 5) { + result = 3; + } + } else if (orientation == 6) { + if (rotation == 0x50) { + result = 0; + } else if (rotation == 0x51) { + result = 1; + } else if (rotation == 1) { + result = 3; + } else if (rotation == 7) { + result = 2; + } else if (rotation == 3) { + result = 4; + } else if (rotation == 5) { + result = 5; + } + } + return result; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2bf3b9ae5..fc1e03efe 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39657,7 +39657,7 @@ SHC_3BB0A8C1_0x004FA000 | 0.0% | Pending SHC_3BB0A8C1_0x004FA2D0 | 0.0% | Pending -SHC_3BB0A8C1_0x004FA460 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA460 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004FA550 | 100.0% | Reimplemented From 39e762a054b42ff19b45f3a71a6772131e4c81bc Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:58:35 +0200 Subject: [PATCH 149/252] header: make the dust cloud counters and terrain index signed generateDustClouds divides SEC_Section1052 with cdq/idiv in the original, so the counters and temporaryTerrainTypeIndex are int, not undefined4. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TileMapState.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/Map/TileMapState.hpp b/src/OpenSHC/Map/TileMapState.hpp index 578e21a69..7edd3b5b5 100644 --- a/src/OpenSHC/Map/TileMapState.hpp +++ b/src/OpenSHC/Map/TileMapState.hpp @@ -93,10 +93,10 @@ namespace Map { int maxPitchDitchCount; // 0x00552904 length: 4 undefined1 padding_0x552908[4]; // 0x00552908 length: 4 short specialAreasArray[8]; // 0x0055290C length: 16 - undefined4 temporaryTerrainTypeIndex; // 0x0055291C length: 4 - undefined4 SEC_Section1052; // 0x00552920 length: 4 - undefined4 SEC_Section1053; // 0x00552924 length: 4 - undefined4 SEC_Section1054; // 0x00552928 length: 4 + int temporaryTerrainTypeIndex; // 0x0055291C length: 4 + int SEC_Section1052; // 0x00552920 length: 4 + int SEC_Section1053; // 0x00552924 length: 4 + int SEC_Section1054; // 0x00552928 length: 4 int temporaryTerrainTypeArray[1000]; // 0x0055292C length: 4000 int temporaryTerrainTypeBinaryArray[1000]; // 0x005538CC length: 4000 undefined4 forceUpdateLogicalAndMiscDisplayLayers; // 0x0055486C length: 4 From 776f4e001a80764c14f49b9f2556685a8c4e62c4 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:58:43 +0200 Subject: [PATCH 150/252] reimplement: SHC_3BB0A8C1_0x004FC490 54.14% 56.42% array base regalloc --- .../Map/TileMapState/generateDustClouds.cpp | 70 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/generateDustClouds.cpp diff --git a/src/OpenSHC/Map/TileMapState/generateDustClouds.cpp b/src/OpenSHC/Map/TileMapState/generateDustClouds.cpp new file mode 100644 index 000000000..fd6b234fe --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/generateDustClouds.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Entities::EntityType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC490 + void TileMapState::generateDustClouds() + { + short seed = SEC_RNG::instance.currentNumber2; + int random = SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + this->SEC_Section1052 = this->SEC_Section1052 + 1; + if (random % 500 == this->SEC_Section1052 % 500) { + this->SEC_Section1053 = random % 0xb4; + } + if (random % 0x4b0 == this->SEC_Section1052 % 0x4b0) { + this->SEC_Section1054 = random % 0xb4; + } + if (this->SEC_Section1053 != 0) { + this->SEC_Section1053 = this->SEC_Section1053 - 1; + } + if (this->SEC_Section1054 != 0) { + this->SEC_Section1054 = this->SEC_Section1054 - 1; + } + + for (int i = 0; i < this->temporaryTerrainTypeIndex; i++) { + int tile = this->temporaryTerrainTypeArray[i]; + /* one tile out of every 64 puffs, selected by the tile's own random value */ + if ((short)(this->RandomLayer[tile] ^ seed) % 64 != this->SEC_Section1052 % 64) { + continue; + } + int stage = this->temporaryTerrainTypeBinaryArray[i]; + if (stage == 0) { + if (this->SEC_Section1054 != 0) { + continue; + } + } else { + if (this->SEC_Section1053 != 0) { + continue; + } + if (stage != 1) { + stage = 2; + } + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(0, 0, 0, + (tile - DAT_ViewportRenderState::instance.translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]].addXgetTile) * 8 + 4, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile] * 8 + 4, this->HeightLayer[tile], 0, 0, 0, + OpenSHC::Map::Entities::ET_DUST_CLOUD, stage); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fc1e03efe..653c598be 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41087,7 +41087,7 @@ SHC_3BB0A8C1_0x004FC280 | 85.2% | XYPair base regalloc SHC_3BB0A8C1_0x004FC340 | 62.4% | LogicLayer walk regalloc -SHC_3BB0A8C1_0x004FC490 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC490 | 54.1% | 56.42% array base regalloc SHC_3BB0A8C1_0x004FC650 | 45.5% | orientation chain regalloc From 49f1ea3c3ec57874106eddaa14718c5b156b521e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:58:43 +0200 Subject: [PATCH 151/252] reimplement: SHC_3BB0A8C1_0x00514520 75.32% 75.63% spill order --- .../Map/TileMapState/placeKillingPit.cpp | 89 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeKillingPit.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeKillingPit.cpp b/src/OpenSHC/Map/TileMapState/placeKillingPit.cpp new file mode 100644 index 000000000..df9b8323e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeKillingPit.cpp @@ -0,0 +1,89 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00514520 + void TileMapState::placeKillingPit(int playerID, uint x, uint y, undefined4 buildingType, uint sizeIndex, + int buildingState, int height) + { + /* the original masks the terrain bits once, before the building is even created */ + int grassOrScrub = this->Logic2Layer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x] + & (OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS | OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB); + int index = 0; + int buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, x, y, height, + (BuildingType)(int)(short)buildingType, sizeIndex, playerID, buildingState); + this->placedBuildingID = buildingID; + if ((short)buildingType != 0x43) { + height = height - 4; + if (height < 0) { + height = 0; + } + } + + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, sizeIndex); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + if (index < 0x24) { + DAT_BuildingsState::instance.buildings[buildingID].tileRefs[index] = tile; + } + this->HeightLayer[tile] = (byte)height; + this->BuildingLayer[tile] = (short)buildingID; + this->BuildingWasLayer[tile] = (uchar)(short)buildingType; + if ((short)buildingType != 0x43) { + /* bug:fixme: a pit dug in grass comes back as thick scrub, not as the terrain it replaced */ + Logic2 terrain; + if (grassOrScrub == 0) { + terrain = OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + } else { + terrain = OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)( + playerID, tile, this->buildingY + y, 3, OpenSHC::Map::LogicHelpers::L_NONE, terrain); + } + index++; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 653c598be..52a140208 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44745,7 +44745,7 @@ SHC_3BB0A8C1_0x00512940 | 76.0% | Od stack slot order differs SHC_3BB0A8C1_0x00514480 | 40.0% | logic masks merged by cl -SHC_3BB0A8C1_0x00514520 | 0.0% | Pending +SHC_3BB0A8C1_0x00514520 | 75.3% | 75.63% spill order SHC_3BB0A8C1_0x005146D0 | 0.0% | Pending From db0a0b4e4731089829a679a03c1679e0e78c2d70 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:58:44 +0200 Subject: [PATCH 152/252] reimplement: SHC_3BB0A8C1_0x004FA2D0 47.39% 47.37% cold block layout regal --- .../TileMapState/checkDrawbridgePlacement.cpp | 97 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/checkDrawbridgePlacement.cpp diff --git a/src/OpenSHC/Map/TileMapState/checkDrawbridgePlacement.cpp b/src/OpenSHC/Map/TileMapState/checkDrawbridgePlacement.cpp new file mode 100644 index 000000000..820a054af --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/checkDrawbridgePlacement.cpp @@ -0,0 +1,97 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + using OpenSHC::Map::Buildings::BuildingLogicalState; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA2D0 + void TileMapState::checkDrawbridgePlacement(int x, int y) + { + if (this->buildingPlacementFail != FALSE) { + return; + } + this->buildingPlacementFail = TRUE; + + for (int rotation = 0; rotation < 4; rotation++) { + int buildings[9]; + int count = 0; + do { + uint offsetY = DAT_TerrainDefinedData::instance.drawBridgeOffsets[rotation][count].y + y; + int offsetX = DAT_TerrainDefinedData::instance.drawBridgeOffsets[rotation][count].x; + buildings[count] = 0; + if ((uint)(offsetX + x) > 399 || offsetY > 399) { + break; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[offsetY * 400 + offsetX + x] == 0) { + break; + } + int tile = DAT_ViewportRenderState::instance.translationMatrix[offsetY].addXgetTile + offsetX + x; + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + buildings[count] = this->BuildingLayer[tile]; + count++; + } while (count < 9); + + if (buildings[0] == 0) { + continue; + } + if (DAT_BuildingsState::instance.buildings[buildings[0]].logicalState != OpenSHC::Map::Buildings::BLS_NORMAL) { + continue; + } + int span; + if (DAT_BuildingsState::instance.buildings[buildings[0]].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE) { + span = 7; + } else { + if (DAT_BuildingsState::instance.buildings[buildings[0]].buildingType != OpenSHC::Map::Buildings::BT_GATEHOUSESMALL) { + continue; + } + span = 5; + } + /* the gatehouse faces along one axis, so only two of the four rotations can carry a bridge */ + if (DAT_BuildingsState::instance.buildings[buildings[0]].buildingVariation == 0x51) { + if (rotation == 1 || rotation == 3) { + continue; + } + } else if (DAT_BuildingsState::instance.buildings[buildings[0]].buildingVariation == 0x50 + && (rotation == 0 || rotation == 2)) { + continue; + } + + int matching = 0; + for (int i = 0; i < span; i++) { + if (buildings[i] == buildings[0]) { + matching++; + } + } + if (matching == span) { + this->buildingPlacementFail = FALSE; + this->uiBuildingRotation = rotation * 2; + this->field127_0x554944 = this->uiBuildingRotation * 25; + return; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 52a140208..c4a55814f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39655,7 +39655,7 @@ SHC_3BB0A8C1_0x004F9F00 | 73.0% | microX/microY regalloc SHC_3BB0A8C1_0x004FA000 | 0.0% | Pending -SHC_3BB0A8C1_0x004FA2D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA2D0 | 47.4% | 47.37% cold block layout regal SHC_3BB0A8C1_0x004FA460 | 100.0% | Reimplemented From 34400890da38d8f54903b76df2d6674c834df49e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 28 Sep 2026 23:58:44 +0200 Subject: [PATCH 153/252] reimplement: SHC_3BB0A8C1_0x005024F0 51.75% 47.37% index spill regalloc --- .../isValidCastleSiteLocation.cpp | 118 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isValidCastleSiteLocation.cpp diff --git a/src/OpenSHC/Map/TileMapState/isValidCastleSiteLocation.cpp b/src/OpenSHC/Map/TileMapState/isValidCastleSiteLocation.cpp new file mode 100644 index 000000000..af13fd19f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isValidCastleSiteLocation.cpp @@ -0,0 +1,118 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005024F0 + BOOLEnum TileMapState::isValidCastleSiteLocation(int x, uint y, int cbt) + { + int baseTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + uint baseY = y; + /* x is reused as the count of tiles that qualified */ + x = 0; + + int enemyRange; + int searchRange; + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + enemyRange = 15; + searchRange = 7; + } else { + enemyRange = 30; + searchRange = 30; + } + + int tile = baseTile; + for (int index = 0; index < 9; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(0, index, &tile, (int*)&y, baseTile, baseY); + /* the brush call may move both, so the original keeps its own copies for later use */ + int brushTile = tile; + uint brushY = y; + if (this->OrganismLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0) { + continue; + } + if (this->BuildingLayer[tile] != 0) { + continue; + } + if ((this->LogicLayer[tile] + & (L_WALL_OR_GATEHOUSE | L_BOULDERS | L_IRON | L_RIVER | L_FORD | L_MARSH)) + != 0) { + continue; + } + if ((this->LogicLayer[tile] & (L_SEA | L_PLAIN1_AND_FARM | L_ROCKY)) != 0) { + continue; + } + + uint brushX = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, DAT_PathFindingState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID, brushX, y, enemyRange) + != FALSE) { + continue; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + int buildRange = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getCastleBuildRangeForMapSize, this)(); + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, DAT_PathFindingState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID, brushX, brushY, searchRange, -1, -1, buildRange + 5) + != 0) { + continue; + } + } + + /* a moat site must be clear of moat, a moat-fill site must sit on one */ + if (cbt == 0x6a) { + if ((this->LogicLayer[brushTile] & (L_MOAT | L_MOAT_DUG_OR_PLANNED)) == 0) { + x = x + 1; + } + } else if (cbt != 0x6b || (this->LogicLayer[brushTile] & L_MOAT_DUG_OR_PLANNED) != 0) { + x = x + 1; + } + } + return (BOOLEnum)(x != 0); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c4a55814f..dbede0203 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41573,7 +41573,7 @@ SHC_3BB0A8C1_0x00502110 | 0.0% | Pending SHC_3BB0A8C1_0x00502390 | 28.1% | brush loop regalloc -SHC_3BB0A8C1_0x005024F0 | 0.0% | Pending +SHC_3BB0A8C1_0x005024F0 | 51.8% | 47.37% index spill regalloc SHC_3BB0A8C1_0x00502680 | 0.0% | Pending From 5a72cded3eb01322287e8eff5d8e8a714bda1c61 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 00:10:59 +0200 Subject: [PATCH 154/252] reimplement: SHC_3BB0A8C1_0x00508540 52.94% 55.63% operand order regalloc --- .../Map/TileMapState/placeStockpile.cpp | 94 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeStockpile.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeStockpile.cpp b/src/OpenSHC/Map/TileMapState/placeStockpile.cpp new file mode 100644 index 000000000..e7b718403 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeStockpile.cpp @@ -0,0 +1,94 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" + +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508540 + void TileMapState::placeStockpile(int playerID, int x, int y, undefined4 buildingType, undefined4 param_5, + int variation, int averageHeight) + { + int uid = DAT_GameCore::instance.uniqueGameObjectTracker; + byte height = (char)averageHeight + 10; + byte wallOwner = (char)playerID - 1; + int type = (short)buildingType; + + int buildingID; + for (int part = 0; part < 4; part++) { + buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, + DAT_TerrainDefinedData::instance.Stockpile_BuildingPartsOffsets[part].x + x, DAT_TerrainDefinedData::instance.Stockpile_BuildingPartsOffsets[part].y + y, + averageHeight + 10, (BuildingType)type, 2, playerID, variation); + DAT_BuildingsState::instance.buildings[buildingID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[buildingID].field125_0x190 = part + 1; + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 2); + index++; + int tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.Stockpile_BuildingPartsOffsets[part].y + this->buildingY + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.Stockpile_BuildingPartsOffsets[part].x + x + this->buildingX; + this->HeightLayer[tile] = height; + /* the stockpile body itself cannot be walked over */ + this->LogicLayer[tile] = this->LogicLayer[tile] | (L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE | L_BUILDING); + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | wallOwner; + this->BuildingLayer[tile] = (ushort)buildingID; + this->BuildingWasLayer[tile] = (uchar)buildingType; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + + this->placedBuildingID = buildingID; + /* the surrounding tiles carry the stockpile graphic but stay walkable */ + for (int slot = 0; slot < 9; slot++) { + int tile = DAT_ViewportRenderState::instance.translationMatrix[DAT_TerrainDefinedData::instance.StockpilePathableOffsets[slot].y + y].addXgetTile + + DAT_TerrainDefinedData::instance.StockpilePathableOffsets[slot].x + x; + this->LogicLayer[tile] = this->LogicLayer[tile] | (L_STOCKPILEUnk | L_WALL_OR_GATEHOUSE); + this->HeightLayer[tile] = height; + this->AlphaGFXLayer[tile] = (ushort)buildingID; + this->BuildingWasLayer[tile] = (uchar)buildingType; + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | wallOwner; + this->ChangedLayer[tile] = 2; + } + + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < DAT_BuildingsState::instance.buildings[buildingID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index dbede0203..b09edf378 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42155,7 +42155,7 @@ SHC_3BB0A8C1_0x00508030 | 61.1% | 68.42% x/y param reuse regallo SHC_3BB0A8C1_0x00508250 | 0.0% | Pending -SHC_3BB0A8C1_0x00508540 | 0.0% | Pending +SHC_3BB0A8C1_0x00508540 | 52.9% | 55.63% operand order regalloc SHC_3BB0A8C1_0x00508590 | 0.0% | Pending From 84f3358d0d3d7e1a7be20a6a9258dcafcd71fb9d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 00:11:00 +0200 Subject: [PATCH 155/252] reimplement: SHC_3BB0A8C1_0x00501A20 91.67% 84.72% regalloc --- .../updateShowHiLayerOrResetChangedLayer.cpp | 94 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateShowHiLayerOrResetChangedLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateShowHiLayerOrResetChangedLayer.cpp b/src/OpenSHC/Map/TileMapState/updateShowHiLayerOrResetChangedLayer.cpp new file mode 100644 index 000000000..5c22df355 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateShowHiLayerOrResetChangedLayer.cpp @@ -0,0 +1,94 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_RotateMapOrPullDownTerrain.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00501A20 + void TileMapState::updateShowHiLayerOrResetChangedLayer() + { + int importHeight = 0; + this->refreshRelatedTwo = 0; + if (this->refreshCertainTileMap == 0) { + return; + } + + this->counter1 = this->counter1 + 1; + this->refreshCertainTileMap_old = this->refreshCertainTileMap; + this->refreshRelatedOne = 0; + for (int row = 0; row < 256; row++) { + int target = ((uint)row >> 2) + 1; + /* the pull-down eases towards the target in steps that shrink as it gets closer */ + int step; + if (this->refreshCertainTileMap == 3) { + step = this->heightBasedScreenYOffset[row] - target; + } else if (this->refreshCertainTileMap == 4) { + step = row - this->heightBasedScreenYOffset[row]; + } else { + step = 0; + } + if (step > 60) { + step = 30; + } else if (step > 40) { + step = 20; + } else if (step > 30) { + step = 14; + } else if (step > 20) { + step = 8; + } else if (step > 10) { + step = 4; + } else if (step > 6) { + step = 3; + } else if (step > 2) { + step = 2; + } else if (step > 0) { + step = 1; + } else { + step = 0; + } + + if (this->refreshCertainTileMap == 1) { + this->heightBasedScreenYOffset[row] = target; + } else if (this->refreshCertainTileMap == 2) { + this->heightBasedScreenYOffset[row] = row; + } else if (this->refreshCertainTileMap == 3) { + this->heightBasedScreenYOffset[row] = this->heightBasedScreenYOffset[row] - step; + if (this->heightBasedScreenYOffset[row] > target) { + importHeight = 1; + } + } else if (this->refreshCertainTileMap == 4) { + this->heightBasedScreenYOffset[row] = this->heightBasedScreenYOffset[row] + step; + if (this->heightBasedScreenYOffset[row] != row) { + importHeight = 1; + } + } + } + + this->refreshRelatedTwo = 1; + if (importHeight != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::rebuildShowHiLayerFromHeights, this)(); + return; + } + if (this->refreshCertainTileMap == 4 || this->refreshCertainTileMap == 2) { + this->refreshRelatedOne = 1; + } else { + this->refreshRelatedOne = 0; + this->refreshRelatedTwo = 2; + } + this->refreshCertainTileMap = 0; + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setChangedLayerToThreeAndMapping0x40x40, this)(); + this->counter1 = 0; + DAT_RotateMapOrPullDownTerrain::instance = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b09edf378..83625ee6b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41543,7 +41543,7 @@ SHC_3BB0A8C1_0x005017A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005017C0 | 0.0% | Pending -SHC_3BB0A8C1_0x00501A20 | 0.0% | Pending +SHC_3BB0A8C1_0x00501A20 | 91.7% | 84.72% regalloc SHC_3BB0A8C1_0x00501B90 | 75.0% | orientation switch regalloc From 7df5c1b8ddcf7e621ac1861d10d9c1e326ffdf94 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 00:11:00 +0200 Subject: [PATCH 156/252] reimplement: SHC_3BB0A8C1_0x004FA760 56.27% 61.02% offset array partition --- ...hBuildingsInKeepsConstructionFootprint.cpp | 97 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp diff --git a/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp b/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp new file mode 100644 index 000000000..b6dc52d63 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp @@ -0,0 +1,97 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingLogicalState; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA760 + void TileMapState::demolishBuildingsInKeepsConstructionFootprint(undefined4 param_1, int x, int y, + undefined4 buildingType, int sizeIndex, int param_6, int param_7) + { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, sizeIndex); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + index++; + } while (index < this->constructionTileCount); + + /* the keep drags three towers and two outbuildings with it, laid out per keep variant */ + int variant = (short)buildingType - 0x28; + { + int tile = DAT_ViewportRenderState::instance.translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[variant][0].y + y].addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[variant][0].x + x; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + } + + { + int tile = DAT_ViewportRenderState::instance.translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[variant][1].y + y].addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[variant][1].x + x; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + } + + { + int tile = DAT_ViewportRenderState::instance.translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[variant][2].y + y].addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[variant][2].x + x; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + } + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 7); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.unkXYOffsets_0x384[variant * 4].yOffset].addXgetTile + this->buildingX + x + + DAT_TerrainDefinedData::instance.unkXYOffsets_0x384[variant * 4].xOffset; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + index++; + } while (index < this->constructionTileCount); + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 5); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.field132_0x3c4[variant * 4 + 4].yOffset].addXgetTile + this->buildingX + x + + DAT_TerrainDefinedData::instance.field132_0x3c4[variant * 4 + 4].xOffset; + if (this->BuildingLayer[tile] != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); + } + index++; + } while (index < this->constructionTileCount); + + for (int buildingID = 1; buildingID < 2000; buildingID++) { + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == OpenSHC::Map::Buildings::BLS_REMOVE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 83625ee6b..685d53a3e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40343,7 +40343,7 @@ SHC_3BB0A8C1_0x004FA759 | 0.0% | Pending SHC_3BB0A8C1_0x004FA75A | 0.0% | Pending -SHC_3BB0A8C1_0x004FA760 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA760 | 56.3% | 61.02% offset array partition SHC_3BB0A8C1_0x004FA8D0 | 0.0% | Pending From 9fc3f4a0c1d3261f124416acda0396c7e9352571 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 00:11:00 +0200 Subject: [PATCH 157/252] reimplement: SHC_3BB0A8C1_0x004FBE70 87.16% 85.48% regalloc --- .../isTileSuitableForBrushPlacement.cpp | 76 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isTileSuitableForBrushPlacement.cpp diff --git a/src/OpenSHC/Map/TileMapState/isTileSuitableForBrushPlacement.cpp b/src/OpenSHC/Map/TileMapState/isTileSuitableForBrushPlacement.cpp new file mode 100644 index 000000000..e314f618a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isTileSuitableForBrushPlacement.cpp @@ -0,0 +1,76 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FBE70 + BOOLEnum TileMapState::isTileSuitableForBrushPlacement(int tile, uint x, uint y) + { + byte height = this->HeightLayer[tile]; + /* the tile suits a brush as soon as it stands above any one of its eight neighbours */ + uint neighbourY = y - 1; + if (x <= 399 && neighbourY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + x] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y - 1].addXgetTile + x]) > 0) { + return TRUE; + } + uint neighbourX = x + 1; + if (neighbourX <= 399 && neighbourY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + neighbourX] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y - 1].addXgetTile + x + 1]) > 0) { + return TRUE; + } + if (neighbourX <= 399 && y <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + neighbourX] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x + 1]) > 0) { + return TRUE; + } + neighbourY = y + 1; + if (neighbourX <= 399 && neighbourY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + neighbourX] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y + 1].addXgetTile + x + 1]) > 0) { + return TRUE; + } + if (x <= 399 && neighbourY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + x] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y + 1].addXgetTile + x]) > 0) { + return TRUE; + } + neighbourX = x - 1; + if (neighbourX <= 399 && neighbourY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + neighbourX] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y + 1].addXgetTile + x - 1]) > 0) { + return TRUE; + } + if (neighbourX <= 399 && y <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + neighbourX] != 0 + && (int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x - 1]) > 0) { + return TRUE; + } + + if (MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, DAT_ViewportRenderState::ptr)( + neighbourX, y - 1) + == FALSE) { + return FALSE; + } + if ((int)(height - this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[y - 1].addXgetTile + x - 1]) < 1) { + return FALSE; + } + return TRUE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 685d53a3e..a0bc99658 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41079,7 +41079,7 @@ SHC_3BB0A8C1_0x004FBD70 | 0.0% | Pending SHC_3BB0A8C1_0x004FBD80 | 38.7% | brush step regalloc -SHC_3BB0A8C1_0x004FBE70 | 0.0% | Pending +SHC_3BB0A8C1_0x004FBE70 | 87.2% | 85.48% regalloc SHC_3BB0A8C1_0x004FC0B0 | 0.0% | Pending From 812d1c027c749f3eec348fc3ccbb4ae9b19595c2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 13:59:28 +0200 Subject: [PATCH 158/252] header: repartition the keep outbuilding offsets in TerrainDefinedData demolishBuildingsInKeepsConstructionFootprint indexes 0x384 and 0x3e4 with a stride of 0x20 per keep variant, so the region is two [3][4] arrays of Point8IntXY rather than unkXYOffsets_0x384[8] + field132_0x3c4[8] + padding. The span is unchanged (0x384..0x444); the one caller in the branch is updated to the new names. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TerrainDefinedData.hpp | 5 ++--- .../demolishBuildingsInKeepsConstructionFootprint.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/Map/TerrainDefinedData.hpp b/src/OpenSHC/Map/TerrainDefinedData.hpp index b857a9499..4469b9a93 100644 --- a/src/OpenSHC/Map/TerrainDefinedData.hpp +++ b/src/OpenSHC/Map/TerrainDefinedData.hpp @@ -43,9 +43,8 @@ namespace Map { XYPair StockpilePathableOffsets[9]; // 0x000001DC length: 72 undefined1 padding_0x224[64]; // 0x00000224 length: 64 XYPair field130_0x264[3][12]; // 0x00000264 length: 288 - Point8IntXY unkXYOffsets_0x384[8]; // 0x00000384 length: 64 - Point8IntXY field132_0x3c4[8]; // 0x000003C4 length: 64 - undefined1 padding_0x404[64]; // 0x00000404 length: 64 + Point8IntXY keepOutbuildingOffsets_0x384[3][4]; // 0x00000384 length: 96 + Point8IntXY keepOutbuildingOffsets_0x3e4[3][4]; // 0x000003E4 length: 96 XYPair field197_0x444[24]; // 0x00000444 length: 192 undefined1 padding_0x504[8]; // 0x00000504 length: 8 XYPair field206_0x50c; // 0x0000050C length: 8 diff --git a/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp b/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp index b6dc52d63..51f27554a 100644 --- a/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp +++ b/src/OpenSHC/Map/TileMapState/demolishBuildingsInKeepsConstructionFootprint.cpp @@ -65,8 +65,8 @@ namespace Map { index = 0; do { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 7); - int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.unkXYOffsets_0x384[variant * 4].yOffset].addXgetTile + this->buildingX + x - + DAT_TerrainDefinedData::instance.unkXYOffsets_0x384[variant * 4].xOffset; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[variant][0].yOffset].addXgetTile + this->buildingX + x + + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[variant][0].xOffset; if (this->BuildingLayer[tile] != 0) { this->showNoRubbleWhenDestroyingBuilding = 1; MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); @@ -77,8 +77,8 @@ namespace Map { index = 0; do { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 5); - int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.field132_0x3c4[variant * 4 + 4].yOffset].addXgetTile + this->buildingX + x - + DAT_TerrainDefinedData::instance.field132_0x3c4[variant * 4 + 4].xOffset; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[variant][0].yOffset].addXgetTile + this->buildingX + x + + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[variant][0].xOffset; if (this->BuildingLayer[tile] != 0) { this->showNoRubbleWhenDestroyingBuilding = 1; MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(this->BuildingLayer[tile]); From 90bfb132e0b77e8726252ad39086902ec78c8bbf Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 13:59:52 +0200 Subject: [PATCH 159/252] docs: record the shared-block, threshold and named-local diff patterns The clamp-ladder shape is a source-structure decision rather than anything a script can rewrite, so it goes in the diff-pattern list next to the others. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- AGENTS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 9a252b0d4..867567e22 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -141,6 +141,20 @@ Diff patterns that were reliable (more in the cheat sheet): not a source difference. - A mismatching argument count or `ret N` usually means the generated header is wrong; report it instead of working around it. - Diffs can reveal real bugs in existing reimplementations (wrong constants, wrong strides); fix those. +- A decompiled `goto` that lands *after* a shared block (a clamp ladder, a common tail) is usually not a + jump at all: put the block once, after the if/else that feeds it, and give the skipped arm the value the + block maps to itself (`step = 0` for a clamp that leaves 0 alone). MSVC then emits the original's + "jump straight past the block" for that arm on its own. Duplicating the block into each arm instead does + *not* get tail-merged and scores far worse - worth ~38 points on `updateShowHiLayerOrResetChangedLayer`. +- Thresholds in such a ladder are the literals the `cmp` shows, not what the decompiler printed: + `cmp eax, 0x3c; jle` is `step > 60`, and Ghidra renders the same code as `iVar1 < 60`. +- A folded address constant where the original has an `imul` means a named local: we wrote + `(y - 1) * 400 + x` and got one constant, while the original multiplied a `y - 1` local by 400. + Give each reused coordinate its own local and reassign it as the original walks the neighbours. +- An extra 4 bytes of frame with no local to explain it is usually a value the decompiler folded into an + expression but the original held in a variable (a copy taken across a call, a mask computed once). +- A mask applied inside a loop over a value that cannot change was hoisted in the original; look for + `and reg, MASK` before the first call and keep the masked result in a local. ## Agent Skills From fb302a8b957d7dcc4c929e5fee96422909f32ca6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:16:20 +0200 Subject: [PATCH 160/252] reimplement: SHC_3BB0A8C1_0x005160C0 37.64% 48.02% global instance base --- .../prepareAreaForBuildingPlacement.cpp | 106 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/prepareAreaForBuildingPlacement.cpp diff --git a/src/OpenSHC/Map/TileMapState/prepareAreaForBuildingPlacement.cpp b/src/OpenSHC/Map/TileMapState/prepareAreaForBuildingPlacement.cpp new file mode 100644 index 000000000..9a5a45f94 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/prepareAreaForBuildingPlacement.cpp @@ -0,0 +1,106 @@ + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005160C0 + BOOLEnum TileMapState::prepareAreaForBuildingPlacement( + int playerID, uint x, uint y, MappersEnum commandBuildingType, int buildingWidthOrHeight) + { + BOOLEnum result = FALSE; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::storeMinAndMaxHeightOfArea, this)(x, y, buildingWidthOrHeight); + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingWidthOrHeight); + uint tileY = y + this->buildingY; + if (x + this->buildingX > 399 || tileY > 399) { + return FALSE; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[tileY * 400 + x + this->buildingX] == 0) { + return FALSE; + } + int tile = DAT_ViewportRenderState::instance.translationMatrix[tileY].addXgetTile + this->buildingX + x; + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + return FALSE; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + tile, playerID, (MappersEnum)(short)commandBuildingType, 1) + == 1) { + return FALSE; + } + index++; + } while (index < this->constructionTileCount); + + /* the original walks the footprint again through the command parameter */ + commandBuildingType = OpenSHC::Commands::M_MAPPER_NULL; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + commandBuildingType, buildingWidthOrHeight); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + x + this->buildingX; + int buildingID = this->BuildingLayer[tile]; + bool cleared = false; + if (buildingID != 0) { + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WOODCUTTERSHUT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_OXTETHER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_QUARRY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_IRONMINE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WHEATFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_HOPFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_APPLEFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_DAIRYFARM) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, playerID, 50); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFromTerrain, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::updatePrimaryBuildingPlayerDataReferences, + DAT_GameState::ptr)(buildingID); + cleared = true; + } + } else if ((this->LogicLayer[tile] & L_FARM_FIELD_APPLE) != 0) { + buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getFarmThatHasTile, + DAT_BuildingsState::ptr)(tile); + if (buildingID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFromTerrain, this)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::updatePrimaryBuildingPlayerDataReferences, + DAT_GameState::ptr)(buildingID); + cleared = true; + } + } + if (cleared) { + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 0x32c, '\0', DAT_BuildingsState::instance.buildings + buildingID); + result = TRUE; + } + commandBuildingType = (MappersEnum)(commandBuildingType + OpenSHC::Commands::M_MAPPER_AREA); + } while ((int)commandBuildingType < this->constructionTileCount); + return result; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a0bc99658..b3a0cf84c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44775,7 +44775,7 @@ SHC_3BB0A8C1_0x00515DA0 | 36.1% | brush loop regalloc SHC_3BB0A8C1_0x00515F40 | 69.9% | Style pass, asm differs -SHC_3BB0A8C1_0x005160C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005160C0 | 37.6% | 48.02% global instance base SHC_3BB0A8C1_0x005162D0 | 0.0% | Pending From bd35216965246fcfc20d4bc975c21f4a71d89657 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:16:20 +0200 Subject: [PATCH 161/252] reimplement: SHC_3BB0A8C1_0x005111D0 46.43% 49.31% struct base regalloc --- .../findNearestFriendlyMoatTileForDigging.cpp | 112 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/findNearestFriendlyMoatTileForDigging.cpp diff --git a/src/OpenSHC/Map/TileMapState/findNearestFriendlyMoatTileForDigging.cpp b/src/OpenSHC/Map/TileMapState/findNearestFriendlyMoatTileForDigging.cpp new file mode 100644 index 000000000..f087a4fc6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/findNearestFriendlyMoatTileForDigging.cpp @@ -0,0 +1,112 @@ + +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005111D0 + BOOLEnum TileMapState::findNearestFriendlyMoatTileForDigging(int playerID, int unitID, int number) + { + int unitX = DAT_UnitsState::instance.units[unitID].x; + int unitY = DAT_UnitsState::instance.units[unitID].y; + ushort area = this->PathConnectionLayer[DAT_ViewportRenderState::instance.translationMatrix[unitY].addXgetTile + + unitX]; + int best = 1000; + BOOLEnum bestMoatID = ~FALSE; + if (0 < this->currentMoatCount) { + for (int moatID = 0; moatID < this->currentMoatCount; moatID++) { + /* digging works on own moat, filling in works on anyone else's */ + if (number == 1 + && DAT_GameState::instance.mapAndTime.playerTeams[this->moats[moatID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + continue; + } + if (number == 2 + && DAT_GameState::instance.mapAndTime.playerTeams[this->moats[moatID].owner] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + continue; + } + if (this->moats[moatID].stage != number) { + continue; + } + int tile = this->moats[moatID].tile; + if (this->BuildingLayer[tile] != 0 && this->moats[moatID].zeroOrTwo == 0) { + continue; + } + if ((this->LogicLayer[tile] & (L_MOAT_DUG_OR_PLANNED | L_MOAT)) == 0) { + continue; + } + if (this->moats[moatID].someCountDown >= 'd') { + continue; + } + if (this->UnitLayer[tile] != 0 && DAT_UnitsState::instance.units[this->UnitLayer[tile]].someUnitStat4 == 0) { + continue; + } + if (number == 2 + && MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::findTileInSameAreaAndNoTooHeightDifference, this)( + area, tile, this->moats[moatID].y) + == FALSE) { + continue; + } + + byte pathCost = this->SEC_PathfindingCostTileMap1105[this->moats[moatID].owner][tile]; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)( + unitX, unitY, this->moats[moatID].x, this->moats[moatID].y); + int score = DAT_DirectionAlgorithmState::instance.distanceHigh; + int fromTarget; + if (DAT_UnitsState::instance.units[unitID].targetX < 1) { + fromTarget = 0; + } else { + fromTarget = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[unitID].targetX, DAT_UnitsState::instance.units[unitID].targetY, + this->moats[moatID].x, this->moats[moatID].y); + } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + score = score + pathCost * 10; + } + score = fromTarget / 2 + this->moats[moatID].someCountDown + score; + if (score < best) { + bestMoatID = moatID; + best = score; + } + } + + if (bestMoatID == FALSE) { + return FALSE; + } + } + /* bug:fixme: with no moats at all the original indexes moats[-1] here */ + this->moats[bestMoatID].someCountDown = this->moats[bestMoatID].someCountDown + 20; + return bestMoatID; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b3a0cf84c..08c0eccd1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44177,7 +44177,7 @@ SHC_3BB0A8C1_0x00511020 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005110B0 | 84.0% | moat scan regalloc -SHC_3BB0A8C1_0x005111D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005111D0 | 46.4% | 49.31% struct base regalloc SHC_3BB0A8C1_0x00511240 | 0.0% | Pending From a407b18c2495aaaf1c0929267890a032935b216f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:16:20 +0200 Subject: [PATCH 162/252] reimplement: SHC_3BB0A8C1_0x005034A0 54.55% 57.24% regalloc --- .../placeDefensiveStructureTile.cpp | 127 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeDefensiveStructureTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeDefensiveStructureTile.cpp b/src/OpenSHC/Map/TileMapState/placeDefensiveStructureTile.cpp new file mode 100644 index 000000000..c906657ff --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeDefensiveStructureTile.cpp @@ -0,0 +1,127 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumShort": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005034A0 + void TileMapState::placeDefensiveStructureTile(int playerID, uint x, uint y, MappersEnum mapper) + { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::validateWallPlacementAtTile, this)(playerID, x, y, mapper); + if (this->illegalBuild != FALSE) { + return; + } + + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + short command = (short)mapper; + this->DamageLayer[tile] = 0; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + if (command == OpenSHC::Commands::M_MAPPER_WALL) { + this->HeightLayer[tile] = this->DefaultHeightLayer[tile] + 0x5a; + } else if (command == OpenSHC::Commands::M_MAPPER_WOODWALL) { + this->HeightLayer[tile] = this->DefaultHeightLayer[tile] + 0x3c; + } else { + bool crenellated = true; + if (command == OpenSHC::Commands::M_MAPPER_CRENAL) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_CRENEL; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x62; + } else if (command == OpenSHC::Commands::M_MAPPER_CRENAL2) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_CRENEL; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x44; + } else { + crenellated = false; + if (command == OpenSHC::Commands::M_MAPPER_STAIR1) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_STAIRS; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x50; + } else if (command == OpenSHC::Commands::M_MAPPER_STAIR2) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_STAIRS; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x40; + } else if (command == OpenSHC::Commands::M_MAPPER_STAIR3) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_STAIRS; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x30; + } else if (command == OpenSHC::Commands::M_MAPPER_STAIR4) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_STAIRS; + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x20; + } + } + /* a crenel on an odd tile of one axis carries the alternate variation */ + if (crenellated && ((x & 1) == 0) != ((y & 1) == 0)) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_CRENEL_VARIATIONUnk; + } + } + + uint logic = this->LogicLayer[tile]; + this->LogicLayer[tile] + = logic & ~(L_UNKNOWN_WALL_RELATED | L_BOULDERS | L_PEBBLES | L_IRON) | L_WALL_OR_GATEHOUSE; + if ((logic & L_PLAIN2_AND_PITCH) != 0) { + this->LogicLayer[tile] + = logic & ~(L_PLAIN2_AND_PITCH | L_UNKNOWN_WALL_RELATED | L_BOULDERS | L_PEBBLES | L_IRON) + | L_WALL_OR_GATEHOUSE; + this->HeightLayer[tile] = this->HeightLayer[tile] + 4; + } + if ((this->LogicLayer[tile] & L_TREE) != 0 && this->OrganismLayer[tile] < 2000) { + DAT_LandscapeState::instance.trees[this->OrganismLayer[tile]].state = 3; + } + if (command == OpenSHC::Commands::M_MAPPER_WOODWALL) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_UNKNOWN_WALL_RELATED; + } + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | (char)playerID - 1U; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)(y, tile); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoat, this)(tile); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(7, x, y); + if (command != OpenSHC::Commands::M_MAPPER_STAIR1 && command != OpenSHC::Commands::M_MAPPER_STAIR2 + && command != OpenSHC::Commands::M_MAPPER_STAIR3 && command != OpenSHC::Commands::M_MAPPER_STAIR4 + && command != OpenSHC::Commands::M_MAPPER_STAIR5 && command != OpenSHC::Commands::M_MAPPER_STAIR6) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processWallBuildingLoss, DAT_BuildingsState::ptr)(playerID, 1, 0, 0); + } + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 08c0eccd1..05eef6c9f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41651,7 +41651,7 @@ SHC_3BB0A8C1_0x00503491 | 0.0% | Pending SHC_3BB0A8C1_0x00503492 | 0.0% | Pending -SHC_3BB0A8C1_0x005034A0 | 0.0% | Pending +SHC_3BB0A8C1_0x005034A0 | 54.5% | 57.24% regalloc SHC_3BB0A8C1_0x00503720 | 100.0% | Reimplemented From 66ced0d69a69b22627b65bc8e7bede51a7dd8b9c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:16:21 +0200 Subject: [PATCH 163/252] reimplement: SHC_3BB0A8C1_0x00502110 27.04% 28.70% this in edi vs esi rega --- .../Map/TileMapState/useLevelBrush.cpp | 146 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/useLevelBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/useLevelBrush.cpp b/src/OpenSHC/Map/TileMapState/useLevelBrush.cpp new file mode 100644 index 000000000..724519b5a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/useLevelBrush.cpp @@ -0,0 +1,146 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00502110 + void TileMapState::useLevelBrush(int tile, uint y, uint brush, int param_4) + { + int baseTile = tile; + uint baseY = y; + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + + int highest = 0; + /* the original reuses the brush parameter to hold the lowest height seen */ + brush = 200; + if (brushSize > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0) { + if ((int)(uint)this->HeightLayer[tile] > highest) { + highest = this->HeightLayer[tile]; + } + if ((int)(uint)this->HeightLayer[tile] < (int)brush) { + brush = this->HeightLayer[tile]; + } + } + index++; + } while (index < brushSize); + } + + int average = (int)(brush + highest) / 2; + tile = baseTile; + y = baseY; + if (brushSize < 1) { + return; + } + + for (int index = 0; index < brushSize; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, &tile, (int*)&y, baseTile, baseY); + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BORDER | L_BORDER_EDGE)) != 0) { + continue; + } + if ((logic & (L_SEA | L_MARSH)) != 0 && this->unknownZero_0x554904 == 0) { + continue; + } + if ((logic & (L_SEA | L_MARSH)) == 0 && this->unknownZero_0x554904 == 1) { + continue; + } + if ((logic + & (L_WALL_OR_GATEHOUSE | L_BUILDING | L_MOAT_DUG_OR_PLANNED | L_KEEP_NON_MANOR_HOUSE | L_MOAT)) + != 0) { + continue; + } + if (this->BuildingLayer[tile] != 0 || (logic & L_SEA) != 0) { + continue; + } + + if ((logic & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] + 8; + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + /* the tile moves a tenth of the way towards the brush average, plus one */ + byte levelled; + bool levelChanged = true; + if ((int)(uint)this->HeightLayer[tile] < average) { + levelled = (char)((average - (int)(uint)this->HeightLayer[tile]) / 10) + this->HeightLayer[tile] + 1; + } else if ((int)(uint)this->HeightLayer[tile] > average) { + levelled = this->HeightLayer[tile] + - (char)(((int)(uint)this->HeightLayer[tile] - average) / 10) - 1; + } else { + levelChanged = false; + } + if (levelChanged) { + this->HeightLayer[tile] = levelled; + this->Logic2Layer[tile] = 0; + } + if (this->HeightLayer[tile] < 8) { + this->HeightLayer[tile] = 8; + } + if (this->HeightLayer[tile] > 0x9c) { + this->HeightLayer[tile] = 0x9c; + } + this->DefaultHeightLayer[tile] = this->HeightLayer[tile]; + if ((this->LogicLayer[tile] & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] - 8; + } + this->DAT_SomeTile = tile; + this->DAT_SomeY = y; + + /* mark this tile and its eight neighbours changed, through the layer pointers */ + byte* changed = (byte*)this->ptr_ChangedLayer + tile; + int* directionRow = (int*)this->ptr_MovementDirectionTranslationMatrix + y * 8; + changed[1] = 2; + changed[-1] = 2; + changed[0] = 2; + byte* northRow = changed + directionRow[0]; + northRow[-1] = 2; + northRow[1] = 2; + northRow[0] = 2; + changed = changed + directionRow[4]; + changed[-1] = 2; + changed[1] = 2; + changed[0] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)(y, tile); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 05eef6c9f..85aeff6a5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41569,7 +41569,7 @@ SHC_3BB0A8C1_0x00501F50 | 9.7% | one fewer spilled local SHC_3BB0A8C1_0x00501FE0 | 0.0% | Pending -SHC_3BB0A8C1_0x00502110 | 0.0% | Pending +SHC_3BB0A8C1_0x00502110 | 27.0% | 28.70% this in edi vs esi rega SHC_3BB0A8C1_0x00502390 | 28.1% | brush loop regalloc From 6964569266747fedf43f1e33711762b13626ee1b Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:56:34 +0200 Subject: [PATCH 164/252] reimplement: SHC_3BB0A8C1_0x004FB9E0 14.56% 20.90% this in ecx vs esi rega --- .../renderWallPlacementPreview.cpp | 131 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/renderWallPlacementPreview.cpp diff --git a/src/OpenSHC/Map/TileMapState/renderWallPlacementPreview.cpp b/src/OpenSHC/Map/TileMapState/renderWallPlacementPreview.cpp new file mode 100644 index 000000000..7f7baacbd --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/renderWallPlacementPreview.cpp @@ -0,0 +1,131 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB9E0 + void TileMapState::renderWallPlacementPreview(uint x, uint y, short kind) + { + int size = 0; + int base = 0; + if (x > 399) { + return; + } + if (y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + this->buildingPlacementFail = FALSE; + /* every wall kind has its own footprint size and first graphic */ + if (kind == 0) { + size = 1; + base = 0x211; + } else if (kind == 1) { + size = 1; + base = 0x215; + } else if (kind == 2) { + size = 1; + base = 0x219; + } else if (kind == 3) { + size = 1; + base = 0x21d; + } else if (kind == 4) { + size = 2; + base = 0x1d1; + } else if (kind == 5) { + size = 2; + base = 0x1e1; + } else if (kind == 6) { + size = 2; + base = 0x1f1; + } else if (kind == 7) { + size = 2; + base = 0x201; + } else if (kind == 8) { + size = 3; + base = 0x141; + } else if (kind == 9) { + size = 3; + base = 0x165; + } else if (kind == 0xa) { + size = 3; + base = 0x189; + } else if (kind == 0xb) { + size = 3; + base = 0x1ad; + } else { + if (kind == 0xc) { + base = 0x41; + } else if (kind == 0xd) { + base = 0x81; + } else if (kind == 0xe) { + base = 0xc1; + } else if (kind == 0xf) { + base = 0x101; + } + if (base != 0) { + size = 4; + } + } + + int rotation = this->rockOrientation + this->mapOrientation; + if (this->field80_0x554894 == 5) { + rotation = this->mapOrientation; + } + if (rotation > 7) { + rotation = rotation - 8; + } + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BORDER | L_BORDER_EDGE)) != 0) { + return; + } + if ((logic & L_BUILDING) != 0) { + return; + } + if (this->OrganismLayer[tile] != 0) { + return; + } + index++; + } while (index < this->constructionTileCount); + + /* the rotation part of the graphic index does not change over the footprint */ + short variationStep = (short)(rotation / 2) * (short)size * (short)size; + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + index++; + this->ConstructionGFXLayer[DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y] + .addXgetTile + + this->buildingX + x] + = ((short)this->buildingRotationRelatedValue + (short)GMTotalPicturesProcessed::instance[0x38] + + variationStep + base) + - 1; + } while (index < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 85aeff6a5..b78241174 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40581,7 +40581,7 @@ SHC_3BB0A8C1_0x004FB970 | 36.9% | ecx not kept across callee SHC_3BB0A8C1_0x004FB990 | 0.0% | Pending -SHC_3BB0A8C1_0x004FB9E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB9E0 | 14.6% | 20.90% this in ecx vs esi rega SHC_3BB0A8C1_0x004FBC30 | 100.0% | Reimplemented From e88d52405182794dce0b659e22046508810a6513 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:56:34 +0200 Subject: [PATCH 165/252] reimplement: SHC_3BB0A8C1_0x005017C0 42.57% 48.37% spill order regalloc --- .../Map/TileMapState/useEraserBrush.cpp | 119 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/useEraserBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/useEraserBrush.cpp b/src/OpenSHC/Map/TileMapState/useEraserBrush.cpp new file mode 100644 index 000000000..93db8c86d --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/useEraserBrush.cpp @@ -0,0 +1,119 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005017C0 + void TileMapState::useEraserBrush(uint x, uint y, int brush) + { + uint baseY = y; + uint baseX = x; + brush = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + int baseTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + /* the original reuses the x parameter as the tile the brush is walking */ + x = baseTile; + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, DAT_EntityState::ptr)( + baseTile); + + if (brush > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, baseY); + int organism = (short)this->OrganismLayer[x]; + if (organism != 0) { + /* tree ids come first, rock ids are biased by 2000 */ + if (organism >= 2000) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeRock, + DAT_LandscapeState::ptr)(organism - 2000); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, baseX, y); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, + DAT_LandscapeState::ptr)(organism); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(3, baseX, y); + } + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + } + index++; + } while (index < brush); + } + + y = baseY; + if (brush > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, baseY); + this->field151_0x554998 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::validateBuildingPlacementAtTile, this)(0, baseX, y); + if (this->buildingPlacementFail == FALSE) { + if (this->field151_0x554998 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::spawnEraserTileEffect, this)( + 0, DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + baseX); + } else if (this->field131_0x554954 != 0xffffffff) { + /* razing a keep takes the stockpile with it, and the other way round */ + short owner = DAT_BuildingsState::instance.buildings[this->field131_0x554954].owner; + if (this->field131_0x554954 == DAT_GameState::instance.playerDataArray[owner].keep.id + && DAT_GameState::instance.playerDataArray[owner].stockpile.id != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[owner].stockpile.id); + } + if (DAT_BuildingsState::instance.buildings[this->field131_0x554954].buildingType == OpenSHC::Map::Buildings::BT_STOCKPILE + && DAT_GameState::instance.playerDataArray[owner].keep.id != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[owner].keep.id); + } + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, DAT_BuildingsState::ptr)( + this->field131_0x554954); + } + } + index++; + } while (index < brush); + } + + y = baseY; + if (brush > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, baseY); + for (int unit = (short)this->UnitLayer[x]; unit != 0; + unit = DAT_UnitsState::instance.units[unit].nextUnitOnTheSameTile) { + DAT_UnitsState::instance.units[unit].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + } + index++; + } while (index < brush); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b78241174..8a86d9af4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41541,7 +41541,7 @@ SHC_3BB0A8C1_0x00501760 | 0.0% | Pending SHC_3BB0A8C1_0x005017A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005017C0 | 0.0% | Pending +SHC_3BB0A8C1_0x005017C0 | 42.6% | 48.37% spill order regalloc SHC_3BB0A8C1_0x00501A20 | 91.7% | 84.72% regalloc From 0f9c694f6611c8f5d34d3059dc74f7ae0c292184 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:56:35 +0200 Subject: [PATCH 166/252] reimplement: SHC_3BB0A8C1_0x004FA000 33.91% 33.90% pointer local frame --- .../determineBuildingPlacementRotation.cpp | 160 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/determineBuildingPlacementRotation.cpp diff --git a/src/OpenSHC/Map/TileMapState/determineBuildingPlacementRotation.cpp b/src/OpenSHC/Map/TileMapState/determineBuildingPlacementRotation.cpp new file mode 100644 index 000000000..78697b0c0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/determineBuildingPlacementRotation.cpp @@ -0,0 +1,160 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FA000 + void TileMapState::determineBuildingPlacementRotation(int x, int y) + { + if (this->buildingPlacementFail != FALSE) { + this->uiBuildingRotation = 8; + this->field127_0x554944 = 0x80; + return; + } + + /* count, per rotation, how many of its four anchor tiles carry usable wall */ + int walls[4]; + for (int rotation = 0; rotation < 4; rotation++) { + walls[rotation] = 0; + if ((uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 0] + x) <= 399 + && (uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 1] + y) <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 1] + y) * 400 + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 0] + x] + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 1] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 0] + x] + & L_WALL_OR_GATEHOUSE) + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 1] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 0] + x] + & (L_STOCKPILEUnk | L_STAIRS)) + == 0) { + walls[rotation] = 1; + } + if ((uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 2] + x) <= 399 + && (uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 3] + y) <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 3] + y) * 400 + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 2] + x] + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 3] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 2] + x] + & L_WALL_OR_GATEHOUSE) + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 3] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 2] + x] + & (L_STOCKPILEUnk | L_STAIRS)) + == 0) { + walls[rotation] = walls[rotation] + 1; + } + if ((uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 4] + x) <= 399 + && (uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 5] + y) <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 5] + y) * 400 + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 4] + x] + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 5] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 4] + x] + & L_WALL_OR_GATEHOUSE) + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 5] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 4] + x] + & (L_STOCKPILEUnk | L_STAIRS)) + == 0) { + walls[rotation] = walls[rotation] + 1; + } + if ((uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 6] + x) <= 399 + && (uint)(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 7] + y) <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[(DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 7] + y) * 400 + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 6] + x] + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 7] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 6] + x] + & L_WALL_OR_GATEHOUSE) + != 0 + && (this->LogicLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 7] + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2465_0x1e4c[rotation * 8 + 6] + x] + & (L_STOCKPILEUnk | L_STAIRS)) + == 0) { + walls[rotation] = walls[rotation] + 1; + } + } + + bool decided = false; + if (walls[0] == 4) { + if (walls[3] == 4) { + this->uiBuildingRotation = 7; + decided = true; + } else if (walls[1] == 4) { + this->uiBuildingRotation = 1; + decided = true; + } + } + if (!decided && walls[2] == 4) { + if (walls[3] == 4) { + this->uiBuildingRotation = 5; + decided = true; + } else if (walls[1] == 4) { + this->uiBuildingRotation = 3; + decided = true; + } + } + if (!decided) { + if (walls[0] == 4) { + this->uiBuildingRotation = 0; + } else if (walls[1] == 4) { + this->uiBuildingRotation = 2; + } else if (walls[2] == 4) { + this->uiBuildingRotation = 4; + } else if (walls[3] == 4) { + this->uiBuildingRotation = 6; + } else { + this->uiBuildingRotation = 8; + } + } + + int relative; + if (this->uiBuildingRotation == 8) { + relative = 8; + } else { + relative = this->uiBuildingRotation - this->mapOrientation; + if (relative < 0) { + this->field127_0x554944 = (relative + 8) * 0x10; + return; + } + } + this->field127_0x554944 = relative << 4; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8a86d9af4..032d76ff7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39653,7 +39653,7 @@ SHC_3BB0A8C1_0x004F9DF0 | 97.1% | buildingType chain regalloc SHC_3BB0A8C1_0x004F9F00 | 73.0% | microX/microY regalloc -SHC_3BB0A8C1_0x004FA000 | 0.0% | Pending +SHC_3BB0A8C1_0x004FA000 | 33.9% | 33.90% pointer local frame SHC_3BB0A8C1_0x004FA2D0 | 47.4% | 47.37% cold block layout regal From a61159e1c55608eefdb8b9afdda3ce27c4451548 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 14:56:35 +0200 Subject: [PATCH 167/252] reimplement: SHC_3BB0A8C1_0x00515A20 34.07% 54.84% x/y regalloc swap --- .../TileMapState/clearBuildingFromTerrain.cpp | 96 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/clearBuildingFromTerrain.cpp diff --git a/src/OpenSHC/Map/TileMapState/clearBuildingFromTerrain.cpp b/src/OpenSHC/Map/TileMapState/clearBuildingFromTerrain.cpp new file mode 100644 index 000000000..885a7a85c --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/clearBuildingFromTerrain.cpp @@ -0,0 +1,96 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00515A20 + void TileMapState::clearBuildingFromTerrain(int buildingID) + { + uint y = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + uint size = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + uint x = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KILLINGPIT) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::validateBuildingPlacementAtTile, this)( + DAT_BuildingsState::instance.buildings[buildingID].owner, x, y); + if (this->buildingPlacementFail != FALSE) { + return; + } + } + + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_STOCKPILE) { + if (DAT_BuildingsState::instance.buildings[buildingID].field125_0x190 == 1) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearStockpileFootprintTiles, this)(x, y); + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearFixedSizeTwoBuildingFootprint, this)(x, y); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateAreaBasedOnSurrounding, this)(x, y, size); + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WHEATFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_HOPFARM) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndResetUnits, this)(x, y, size); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingDisplayFlagsAndEntities, this)(buildingID, 1); + int surfaceArea; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WHEATFARM) { + surfaceArea = 36; + } else { + surfaceArea = 24; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingTilesAndTrees, this)(buildingID, surfaceArea); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::unmarkBuildingFootprintFlag, this)(x, y, 9); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateAreaBasedOnSurrounding, this)(x, y, 9); + size = 6; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_DAIRYFARM) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndResetUnits, this)(x, y, size); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingDisplayFlagsAndEntities, this)(buildingID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingTilesAndTrees, this)(buildingID, 0x1b); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::unmarkBuildingFootprintFlag, this)(x, y, 10); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateAreaBasedOnSurrounding, this)(x, y, 10); + size = 6; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_APPLEFARM) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndResetUnits, this)(x, y, size); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingDisplayFlagsAndEntities, this)(buildingID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingTilesAndTrees, this)(buildingID, 8); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::unmarkBuildingFootprintFlag, this)(x, y, 0xb); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateAreaBasedOnSurrounding, this)(x, y, 0xb); + size = 6; + } else { + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearSizeFiveBuildingFootprintAndMoats, this)(x, y); + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_CATAPULT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_TREBUCHET || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_BATTERINGRAM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_SIEGETOWER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_SHIELD || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_FIREBALLISTA) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintWithEdgeRubble, this)(x, y, size); + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndRemoveSiegeTower, this)(x, y, size); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndResetUnits, this)(x, y, size); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingFootprintAndResetUnits, this)(x, y, size); + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearBuildingDisplayFlagsAndEntities, this)(buildingID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateAreaBasedOnSurrounding, this)(x, y, size); + } + + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(buildingID); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(size + 6, x, y); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 032d76ff7..892f5870e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44767,7 +44767,7 @@ SHC_3BB0A8C1_0x00515680 | 0.0% | Pending SHC_3BB0A8C1_0x00515740 | 0.0% | Pending -SHC_3BB0A8C1_0x00515A20 | 0.0% | Pending +SHC_3BB0A8C1_0x00515A20 | 34.1% | 54.84% x/y regalloc swap SHC_3BB0A8C1_0x00515C80 | 52.6% | ecx not kept across callee From ac343b42f3beedeb55deb6a2afee2112c0f407ea Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:02:32 +0200 Subject: [PATCH 168/252] tools: give the batch build scripts build.bat PDB server fix build.bat gives each worktree its own _MSPDBSRV_ENDPOINT_ and kills its own mspdbsrv.exe before building. build_quiet.py --keep-going calls cmakew directly and syntax_check.py calls cl.exe directly, so neither inherited that, and a server already wedged before the build started survived build.bat kill and still failed with C1090. common.build_env derives the same endpoint name; common.kill_pdb_server stops only this worktree instance; build_quiet.py retries the build once after a C1090/C1033. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- tools/reimplementation-helper/batch/README.md | 9 +++++- .../batch/build_quiet.py | 31 ++++++++++++++----- tools/reimplementation-helper/batch/common.py | 30 ++++++++++++++++++ .../batch/syntax_check.py | 5 +-- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/tools/reimplementation-helper/batch/README.md b/tools/reimplementation-helper/batch/README.md index 3350aea2b..47cbbfa65 100644 --- a/tools/reimplementation-helper/batch/README.md +++ b/tools/reimplementation-helper/batch/README.md @@ -12,7 +12,7 @@ rewrite sources, because the Visual Studio bundled one is too old for `.clang-fo | Script | Purpose | |---|---| -| `build_quiet.py [--keep-going]` | `build.bat RelWithDebInfo OpenSHC.dll`, prints only errors and `BUILD_OK`/`BUILD_FAIL` (build.bat exits 0 even on errors). | +| `build_quiet.py [--keep-going]` | `build.bat RelWithDebInfo OpenSHC.dll`, prints only errors and `BUILD_OK`/`BUILD_FAIL` (build.bat exits 0 even on errors). Retries once on a PDB server error, see the note below. | | `syntax_check.py [substr...]` | `cl /Zs` every (matching) list file serially; finds all compile errors in one pass without linking. | | `reccmp_report.py [--run] pct\|save\|cmp\|diff` | Match % and *normalized* % (call/tail-jump targets and resolver addresses ignored) per function, snapshots, before/after comparison, compact asm diffs. | | `show_functions.py PREFIX [--skip-100]` | Print function bodies under `src/OpenSHC/PREFIX` with their percentages, in the block format `splice_functions.py` reads. | @@ -40,3 +40,10 @@ python commit_progress_batch.py Map/Units "someFunction=LTCG ecx reuse" - A file whose `// FUNCTION:` address has no reccmp entry is reported as `--` / skipped. Check the address against `src/precomp/addresses-SHC-3BB0A8C1.hpp`. - Sources are always written as UTF-8 with LF line endings. +- Every script that runs `cl.exe` sets this worktree's own `_MSPDBSRV_ENDPOINT_` + (`common.build_env`), the same name `build.bat` derives. `mspdbsrv.exe` is a per-user + singleton keyed on that endpoint and each worktree carries its own toolchain copy, so a + shared endpoint makes `cl.exe` talk to the wrong server and fail with + `fatal error C1090: PDB API call failed`. `build_quiet.py` retries once after stopping + this worktree's `mspdbsrv.exe` (`common.kill_pdb_server`, never other worktrees'), which + clears a server that was already wedged before the build started. diff --git a/tools/reimplementation-helper/batch/build_quiet.py b/tools/reimplementation-helper/batch/build_quiet.py index 4b0367ab7..ad3633089 100644 --- a/tools/reimplementation-helper/batch/build_quiet.py +++ b/tools/reimplementation-helper/batch/build_quiet.py @@ -5,13 +5,19 @@ Prints BUILD_OK or BUILD_FAIL as the last line. build.bat exits 0 even on compile errors, so the log is scanned instead of trusting the exit code. --keep-going reruns the build with nmake /K to collect errors from more files. + +The build runs with this worktree's own _MSPDBSRV_ENDPOINT_ (see common.build_env), which is what +build.bat does too; --keep-going bypasses build.bat and would otherwise inherit whatever endpoint +happens to be set. A build that still dies with C1090/C1033 gets one retry after stopping this +worktree's mspdbsrv.exe, because a wedged PDB server survives the kill build.bat does up front. """ import argparse import re import subprocess +import sys -from common import TMP +from common import PDB_ERROR_RE, TMP, build_env, kill_pdb_server parser = argparse.ArgumentParser() parser.add_argument("--keep-going", action="store_true") @@ -19,14 +25,25 @@ args = parser.parse_args() log = TMP / "build.log" -with open(log, "w") as out: - subprocess.run(["cmd", "/c", r".\build.bat RelWithDebInfo OpenSHC.dll"], stdout=out, stderr=subprocess.STDOUT) -if args.keep_going: + + +def run_build(): with open(log, "w") as out: - subprocess.run(["cmd", "/c", r".\cmakew --build --preset RelWithDebInfo --target OpenSHC.dll -- /K"], - stdout=out, stderr=subprocess.STDOUT) + subprocess.run(["cmd", "/c", r".\build.bat RelWithDebInfo OpenSHC.dll"], + stdout=out, stderr=subprocess.STDOUT, env=build_env()) + if args.keep_going: + with open(log, "w") as out: + subprocess.run(["cmd", "/c", r".\cmakew --build --preset RelWithDebInfo --target OpenSHC.dll -- /K"], + stdout=out, stderr=subprocess.STDOUT, env=build_env()) + return log.read_text(errors="replace") + + +text = run_build() +if PDB_ERROR_RE.search(text): + print("note: PDB server error, stopping this worktree's mspdbsrv.exe and retrying", file=sys.stderr) + kill_pdb_server() + text = run_build() -text = log.read_text(errors="replace") errors = [line for line in text.splitlines() if re.search(r" error |warning C4700|warning C4715", line) and "U1077" not in line] for line in errors[:args.max]: diff --git a/tools/reimplementation-helper/batch/common.py b/tools/reimplementation-helper/batch/common.py index a5c05e54a..5287dbdbc 100644 --- a/tools/reimplementation-helper/batch/common.py +++ b/tools/reimplementation-helper/batch/common.py @@ -27,6 +27,36 @@ DIFF_JSON = Path("reccmp/dll/diff.json") FUNCTION_RE = re.compile(r"//\s*FUNCTION:\s*STRONGHOLDCRUSADER\s+(0x[0-9A-Fa-f]+)") +# ---------------------------------------------------------------- pdb server + +# mspdbsrv.exe is a per-user singleton keyed on _MSPDBSRV_ENDPOINT_, and every worktree carries its +# own copy of the toolchain. Sharing one endpoint makes cl.exe talk to whichever copy started first +# and fail with "fatal error C1090: PDB API call failed, error code '23'" (or C1033). build.bat +# derives this same name, so setting it here keeps the two in step and also covers the scripts that +# drive cl.exe or cmake directly instead of going through build.bat. +PDB_ENDPOINT = "openshc_" + ROOT.name +PDB_ERROR_RE = re.compile(r"fatal error C10(90|33)") + + +def build_env(): + """Environment for anything that runs cl.exe, with this worktree's PDB endpoint.""" + env = dict(os.environ) + env.setdefault("_MSPDBSRV_ENDPOINT_", PDB_ENDPOINT) + return env + + +def kill_pdb_server(): + """Stop this worktree's mspdbsrv.exe only. + + Killing every instance by image name takes down the PDB server of any other worktree that is + building at the same time and fails their build with the same C1090. + """ + subprocess.run(["powershell", "-NoProfile", "-Command", + "Get-Process mspdbsrv -ErrorAction SilentlyContinue | " + "Where-Object { $_.Path -like '%s*' } | " + "Stop-Process -Force -ErrorAction SilentlyContinue" + % str(ROOT).replace("'", "''")], + capture_output=True) def list_files(existing_only=True): diff --git a/tools/reimplementation-helper/batch/syntax_check.py b/tools/reimplementation-helper/batch/syntax_check.py index 5fde77df5..4f7212a9f 100644 --- a/tools/reimplementation-helper/batch/syntax_check.py +++ b/tools/reimplementation-helper/batch/syntax_check.py @@ -12,7 +12,7 @@ import subprocess import sys -from common import BUILD_DIR, ROOT, TMP, list_files +from common import BUILD_DIR, ROOT, TMP, build_env, list_files commands = json.loads((BUILD_DIR / "compile_commands.json").read_text()) template = next(c["command"] for c in commands if "OpenSHC.dll.dir" in c["command"]) @@ -30,7 +30,8 @@ bat = TMP / "syntax_check.bat" bat.write_text("\n".join(lines) + "\n") -result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True) +result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True, + env=build_env()) errors = [l for l in (result.stdout + result.stderr).splitlines() if " error " in l or "fatal" in l] for line in errors: print(re.sub(r"^.*src.OpenSHC.", "", line)[:260]) From bb5c2b51fd8b335d1494e0677e5c4b407e2dda71 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:21:32 +0200 Subject: [PATCH 169/252] reimplement: SHC_3BB0A8C1_0x004FB4D0 41.13% 43.40% rockType spilled vs reg --- src/OpenSHC/Map/TileMapState/placeRock.cpp | 145 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeRock.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeRock.cpp b/src/OpenSHC/Map/TileMapState/placeRock.cpp new file mode 100644 index 000000000..f5f011b83 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeRock.cpp @@ -0,0 +1,145 @@ + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_OIL; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB4D0 + void TileMapState::placeRock(uint x, uint y, uint kind) + { + int rockType = 0; + int size = 1; + if (x > 399) { + return; + } + if (y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + /* every rock kind has its own footprint size and rock type */ + if ((short)kind == 0) { + rockType = 1; + } else if ((short)kind == 1) { + rockType = 2; + } else if ((short)kind == 2) { + rockType = 3; + } else if ((short)kind == 3) { + rockType = 4; + } else if ((short)kind == 4) { + size = 2; + rockType = 5; + } else if ((short)kind == 5) { + size = 2; + rockType = 6; + } else if ((short)kind == 6) { + size = 2; + rockType = 7; + } else if ((short)kind == 7) { + size = 2; + rockType = 8; + } else if ((short)kind == 8) { + size = 3; + rockType = 9; + } else if ((short)kind == 9) { + size = 3; + rockType = 0xa; + } else if ((short)kind == 0xa) { + size = 3; + rockType = 0xb; + } else if ((short)kind == 0xb) { + size = 3; + rockType = 0xc; + } else { + if ((short)kind == 0xc) { + rockType = 0xd; + } else if ((short)kind == 0xd) { + rockType = 0xe; + } else if ((short)kind == 0xe) { + rockType = 0xf; + } else if ((short)kind == 0xf) { + rockType = 0x10; + } + if (rockType != 0) { + size = 4; + } + } + + /* the original reuses the kind parameter to hold the lowest height under the footprint */ + kind = 1000; + uint highest = 0; + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + return; + } + if ((this->LogicLayer[tile] & L_BUILDING) != 0) { + return; + } + if (this->OrganismLayer[tile] != 0) { + return; + } + if (highest < this->HeightLayer[tile]) { + highest = this->HeightLayer[tile]; + } + if (this->HeightLayer[tile] < kind) { + kind = this->HeightLayer[tile]; + } + index++; + } while (index < this->constructionTileCount); + + byte height = (char)((int)(highest - kind) / 2) + (char)kind; + int rockID = MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::createRock, DAT_LandscapeState::ptr)( + x, y, rockType, size, this->rockOrientation); + index = 0; + short organism = (short)rockID + 2000; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + index++; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + this->buildingX + x; + this->HeightLayer[tile] = height; + this->DefaultHeightLayer[tile] = height; + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_SEA | L_PLAIN2_AND_PITCH | L_BOULDERS | L_PEBBLES | L_IRON | L_RIVER | L_FORD | L_MARSH | L_MOAT + | L_OIL); + this->Logic2Layer[tile] = 0; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_ROCKY; + this->OrganismLayer[tile] = organism; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(9, x, y); + this->forceUpdateMacroLayerFlag = 1; + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 892f5870e..5270300c8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40569,7 +40569,7 @@ SHC_3BB0A8C1_0x004FB360 | 79.0% | ecx not kept across callee SHC_3BB0A8C1_0x004FB3F0 | 34.3% | XYPair stride regalloc -SHC_3BB0A8C1_0x004FB4D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB4D0 | 41.1% | 43.40% rockType spilled vs reg SHC_3BB0A8C1_0x004FB770 | 76.7% | gfx expression regalloc From af898f7957f65a329407be15656681e6a6b79214 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:21:33 +0200 Subject: [PATCH 170/252] reimplement: SHC_3BB0A8C1_0x00508EC0 27.51% 35.40% spill order regalloc --- .../Map/TileMapState/eraseAreaWithBrush.cpp | 134 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/eraseAreaWithBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/eraseAreaWithBrush.cpp b/src/OpenSHC/Map/TileMapState/eraseAreaWithBrush.cpp new file mode 100644 index 000000000..17de30d46 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/eraseAreaWithBrush.cpp @@ -0,0 +1,134 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508EC0 + void TileMapState::eraseAreaWithBrush(uint x, uint y, uint brush) + { + uint baseX = x; + if (x > 399) { + return; + } + if (y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + uint baseTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + /* the original reuses the brush parameter as the saved y and x as the walking tile */ + brush = y; + x = baseTile; + + if (brushSize > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, brush); + if ((this->LogicLayer[x] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + int organism = (short)this->OrganismLayer[x]; + if (organism != 0) { + /* tree ids come first, rock ids are biased by 2000 */ + if (organism >= 2000) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeRock, DAT_LandscapeState::ptr)(organism - 2000); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(8, baseX, y); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(organism); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(3, baseX, y); + } + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + } + index++; + } while (index < brushSize); + } + + y = brush; + if (brushSize > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, brush); + if ((this->LogicLayer[x] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + this->field151_0x554998 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::validateBuildingPlacementAtTile, this)(0, baseX, y); + if (this->buildingPlacementFail == FALSE) { + if (this->field151_0x554998 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::spawnEraserTileEffect, this)( + 0, DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + baseX); + } else if (this->field131_0x554954 != 0xffffffff) { + /* razing a keep takes the stockpile with it, and the other way round */ + short owner = DAT_BuildingsState::instance.buildings[this->field131_0x554954].owner; + if (this->field131_0x554954 == DAT_GameState::instance.playerDataArray[owner].keep.id + && DAT_GameState::instance.playerDataArray[owner].stockpile.id != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[owner].stockpile.id); + } + if (DAT_BuildingsState::instance.buildings[this->field131_0x554954].buildingType == OpenSHC::Map::Buildings::BT_STOCKPILE + && DAT_GameState::instance.playerDataArray[owner].keep.id != 0) { + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[owner].keep.id); + } + this->showNoRubbleWhenDestroyingBuilding = 1; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuildingAndLinkedDuplicates, DAT_BuildingsState::ptr)( + this->field131_0x554954); + } + } + index++; + } while (index < brushSize); + } + + y = brush; + if (brushSize > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, (int*)&x, (int*)&y, baseTile, brush); + if ((this->LogicLayer[x] & (L_BORDER | L_BORDER_EDGE)) != 0) { + return; + } + for (int unit = (short)this->UnitLayer[x]; unit != 0; + unit = DAT_UnitsState::instance.units[unit].nextUnitOnTheSameTile) { + DAT_UnitsState::instance.units[unit].logicalState = OpenSHC::Map::Units::ULS_REMOVE; + } + index++; + } while (index < brushSize); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5270300c8..94e929015 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42765,7 +42765,7 @@ SHC_3BB0A8C1_0x00508DC3 | 0.0% | Pending SHC_3BB0A8C1_0x00508DD0 | 43.1% | extra callee-saved reg -SHC_3BB0A8C1_0x00508EC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00508EC0 | 27.5% | 35.40% spill order regalloc SHC_3BB0A8C1_0x00509180 | 0.0% | Pending From 19b2f95a98f2ce87087e7f07adb555a385290772 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:21:33 +0200 Subject: [PATCH 171/252] reimplement: SHC_3BB0A8C1_0x004FB0C0 50.43% 50.43% two jump tables, slot r --- .../Map/TileMapState/setMiscDisplayLayer.cpp | 126 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setMiscDisplayLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/setMiscDisplayLayer.cpp b/src/OpenSHC/Map/TileMapState/setMiscDisplayLayer.cpp new file mode 100644 index 000000000..d222c5df0 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setMiscDisplayLayer.cpp @@ -0,0 +1,126 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FB0C0 + void TileMapState::setMiscDisplayLayer(int buildingID) + { + if (DAT_BuildingsState::instance.buildings[buildingID].unknownStockpileOrSignpostRelated == 0) { + return; + } + + int x = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + int y = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + uint size = DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + OpenSHC::Map::Buildings::BuildingTypeShort type = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + int typeInt = (short)type; + int offsetIndex = this->mapOrientation / 2 + size * 4; + int workerTile = DAT_TerrainDefinedData::instance.orientationRelativeBuildingTileOffset1[offsetIndex]; + int displayTile = DAT_TerrainDefinedData::instance.orientationRelativeBuildingTileOffset2[offsetIndex]; + int extraTile = -1; + switch (typeInt) { + case OpenSHC::Map::Buildings::BT_IRONMINE: + case OpenSHC::Map::Buildings::BT_PITCHRIG: + case OpenSHC::Map::Buildings::BT_HUNTERSHUT: + case OpenSHC::Map::Buildings::BT_BLACKSMITH: + case OpenSHC::Map::Buildings::BT_BREWERY: + case OpenSHC::Map::Buildings::BT_OILSMELTER: + case OpenSHC::Map::Buildings::BT_STABLES: + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + case OpenSHC::Map::Buildings::BT_TUNNEL: + case OpenSHC::Map::Buildings::BT_FIREBALLISTA: + case OpenSHC::Map::Buildings::BT_MAYPOLE: + case OpenSHC::Map::Buildings::BT_CATAPULT: + case OpenSHC::Map::Buildings::BT_TREBUCHET: + case OpenSHC::Map::Buildings::BT_BATTERINGRAM: + case OpenSHC::Map::Buildings::BT_SIEGETOWER: + case OpenSHC::Map::Buildings::BT_SHIELD: + case OpenSHC::Map::Buildings::BT_UNKNOWN4: + /* these carry the worker on the display tile and the display on the worker tile */ + workerTile = displayTile; + displayTile = DAT_TerrainDefinedData::instance.orientationRelativeBuildingTileOffset1[offsetIndex]; + break; + case OpenSHC::Map::Buildings::BT_DRAWBRIDGE: + switch (this->mapOrientation / 2) { + case 0: + displayTile = 0x13; + extraTile = 6; + break; + case 1: + displayTile = 0x15; + extraTile = 8; + break; + case 2: + displayTile = 5; + extraTile = 0x12; + break; + case 3: + displayTile = 3; + extraTile = 0x10; + } + break; + case OpenSHC::Map::Buildings::BT_GALLOWS: + case OpenSHC::Map::Buildings::BT_GIBBET: + workerTile = -1; + } + + if ((int)size < 3 && type != OpenSHC::Map::Buildings::BT_GIBBET && type != OpenSHC::Map::Buildings::BT_GALLOWS) { + this->MiscDisplayLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x] + = this->MiscDisplayLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x] | 4; + return; + } + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + index++; + this->MiscDisplayLayer[DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + x + this->buildingX] + = this->MiscDisplayLayer[DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + x + + this->buildingX] + & 0xfff3; + } while (index < this->constructionTileCount); + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + x + this->buildingX; + if (typeInt == OpenSHC::Map::Buildings::BT_GRANARY) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 8; + } else if (typeInt == OpenSHC::Map::Buildings::BT_ARMORY) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 8; + } else if (index == workerTile) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 8; + /* fixme: xPosition and the field after it are written as one int */ + *(int*)&DAT_BuildingsState::instance.buildings[buildingID].xPosition = tile; + } + if (index == displayTile) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 4; + DAT_BuildingsState::instance.buildings[buildingID].miscDisplayLayerTile = tile; + } + if (index == extraTile) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0xc; + DAT_BuildingsState::instance.buildings[buildingID].miscDisplayLayerTile = tile; + } + index++; + } while (index < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 94e929015..f4bf4f2d4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -40369,7 +40369,7 @@ SHC_3BB0A8C1_0x004FAEE0 | 55.3% | ecx not kept across callee SHC_3BB0A8C1_0x004FAF70 | 98.5% | offset walk regalloc -SHC_3BB0A8C1_0x004FB0C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FB0C0 | 50.4% | 50.43% two jump tables, slot r SHC_3BB0A8C1_0x004FB2E0 | 0.0% | Pending From 59f58edbb327bc0d6c510a43dab56a4fe4c74b26 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:21:33 +0200 Subject: [PATCH 172/252] reimplement: SHC_3BB0A8C1_0x00502680 19.95% 20.99% highest/lowest spilled --- .../TileMapState/useTerrainHeightBrush.cpp | 143 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/useTerrainHeightBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/useTerrainHeightBrush.cpp b/src/OpenSHC/Map/TileMapState/useTerrainHeightBrush.cpp new file mode 100644 index 000000000..9df9badf3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/useTerrainHeightBrush.cpp @@ -0,0 +1,143 @@ + +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00502680 + void TileMapState::useTerrainHeightBrush(int tile, uint y, uint brush, undefined4 mapper) + { + int baseTile = tile; + uint baseY = y; + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[brush]; + + int highest = 0; + /* the original reuses the brush parameter to hold the lowest height seen */ + brush = 200; + if (brushSize > 0) { + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) == 0) { + if ((int)(uint)this->HeightLayer[tile] > highest) { + highest = this->HeightLayer[tile]; + } + if ((int)(uint)this->HeightLayer[tile] < (int)brush) { + brush = this->HeightLayer[tile]; + } + } + index++; + } while (index < brushSize); + } + + int average = (int)(brush + highest) / 2; + tile = baseTile; + y = baseY; + if (brushSize < 1) { + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + return; + } + + for (int index = 0; index < brushSize; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, &tile, (int*)&y, baseTile, baseY); + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + continue; + } + if ((this->LogicLayer[tile] + & (L_SEA | L_WALL_OR_GATEHOUSE | L_BUILDING | L_KEEP_NON_MANOR_HOUSE | L_MARSH | L_MOAT)) + != 0) { + continue; + } + if (this->BuildingLayer[tile] != 0) { + continue; + } + + this->HeightLayer[tile] = this->HeightLayer[tile] + 1; + if ((short)mapper == 0) { + /* mapper min */ + this->HeightLayer[tile] = 8; + this->Logic2Layer[tile] = this->Logic2Layer[tile] & 0xf3; + } else if ((short)mapper == 1) { + /* mapper max, bug:fixme: is 156 really the maximum height? */ + this->HeightLayer[tile] = 156; + this->LogicLayer[tile] = this->LogicLayer[tile] | 0x8000; + } else if ((short)mapper == 5) { + this->HeightLayer[tile] = 100; + } else if ((short)mapper == 2) { + /* scale towards the brush average, in eighths of the ratio to it */ + int ratio; + if (average != 0) { + ratio = this->HeightLayer[tile] * 100 / average; + } else { + ratio = 100; + } + ratio = ratio / 8 + 100; + ratio = ratio * this->HeightLayer[tile] / 100; + if (ratio > 0x9c) { + ratio = 0x9c; + } + this->HeightLayer[tile] = (byte)ratio; + } + + if ((this->LogicLayer[tile] & L_ROCKY) != 0 && this->OrganismLayer[tile] > 1999) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeRock, DAT_LandscapeState::ptr)( + this->OrganismLayer[tile] - 2000); + } + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_ROCKY; + if (this->HeightLayer[tile] < 8) { + this->HeightLayer[tile] = 8; + } + if (this->HeightLayer[tile] > 0x9c) { + this->HeightLayer[tile] = 0x9c; + } + this->DefaultHeightLayer[tile] = this->HeightLayer[tile]; + if ((this->LogicLayer[tile] & L_RIVER) != 0) { + this->HeightLayer[tile] = this->HeightLayer[tile] - 8; + } + this->DAT_SomeTile = tile; + this->DAT_SomeY = y; + + /* mark this tile and its eight neighbours changed, through the layer pointers */ + byte* changed = (byte*)this->ptr_ChangedLayer + tile; + int* directionRow = (int*)this->ptr_MovementDirectionTranslationMatrix + y * 8; + changed[1] = 2; + changed[-1] = 2; + changed[0] = 2; + byte* northRow = changed + directionRow[0]; + northRow[-1] = 2; + northRow[1] = 2; + northRow[0] = 2; + changed = changed + directionRow[4]; + changed[-1] = 2; + changed[1] = 2; + changed[0] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)(y, tile); + } + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f4bf4f2d4..801e59db3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41575,7 +41575,7 @@ SHC_3BB0A8C1_0x00502390 | 28.1% | brush loop regalloc SHC_3BB0A8C1_0x005024F0 | 51.8% | 47.37% index spill regalloc -SHC_3BB0A8C1_0x00502680 | 0.0% | Pending +SHC_3BB0A8C1_0x00502680 | 19.9% | 20.99% highest/lowest spilled SHC_3BB0A8C1_0x00502950 | 100.0% | Reimplemented From cad51dca14cb9b3c647331a7265cd1316b2924e7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 15:40:54 +0200 Subject: [PATCH 173/252] tools/batch: retry on a fresh PDB endpoint, not just a fresh server The cherry-picked fix recovers from a wedged mspdbsrv.exe by stopping this worktree''s instance and building again. C1090 has a second cause that recovery cannot reach: the endpoint name itself can wedge, outliving every mspdbsrv.exe that uses it, so retrying into the same name fails forever. Six consecutive builds failed that way here. Killing the server did not help, nor did deleting the PCH and both PDBs; the endpoint was correctly unique, not inherited from the environment, and the toolchain binaries matched a worktree that was building fine at that moment. The same tree then built first try under a different endpoint name, which is what identified the cause. build_quiet.py now takes a second retry on a fresh endpoint, and build_env() accepts an explicit one so a caller can pin it for a session. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01A4PvfebpUzaMXy93EutBjJ (cherry picked from commit 2826353e6c2ab3761e2a762ec28cfb6a4a403fb1) (cherry picked from commit 56beea35b96a41c460c93dbc7a3f5f6b6c799a0a) --- .../batch/build_quiet.py | 28 +++++++++++++++---- tools/reimplementation-helper/batch/common.py | 24 ++++++++++++++-- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/tools/reimplementation-helper/batch/build_quiet.py b/tools/reimplementation-helper/batch/build_quiet.py index ad3633089..7e29e9fd9 100644 --- a/tools/reimplementation-helper/batch/build_quiet.py +++ b/tools/reimplementation-helper/batch/build_quiet.py @@ -8,8 +8,16 @@ The build runs with this worktree's own _MSPDBSRV_ENDPOINT_ (see common.build_env), which is what build.bat does too; --keep-going bypasses build.bat and would otherwise inherit whatever endpoint -happens to be set. A build that still dies with C1090/C1033 gets one retry after stopping this -worktree's mspdbsrv.exe, because a wedged PDB server survives the kill build.bat does up front. +happens to be set. A build that dies with C1090/C1033 gets two retries, because that error has two +different causes: + + 1. a wedged PDB server, which survives the kill build.bat does up front -> stop this worktree's + mspdbsrv.exe and build again; + 2. a wedged *endpoint*, which outlives every mspdbsrv.exe using it -> build again on a fresh + endpoint name, since retrying into the same name fails forever. + +The second cost six consecutive builds once, across a regenerated PCH and PDBs, while the same tree +built first try under a different endpoint name. """ import argparse @@ -17,7 +25,7 @@ import subprocess import sys -from common import PDB_ERROR_RE, TMP, build_env, kill_pdb_server +from common import PDB_ERROR_RE, TMP, build_env, fresh_pdb_endpoint, kill_pdb_server parser = argparse.ArgumentParser() parser.add_argument("--keep-going", action="store_true") @@ -27,14 +35,14 @@ log = TMP / "build.log" -def run_build(): +def run_build(endpoint=None): with open(log, "w") as out: subprocess.run(["cmd", "/c", r".\build.bat RelWithDebInfo OpenSHC.dll"], - stdout=out, stderr=subprocess.STDOUT, env=build_env()) + stdout=out, stderr=subprocess.STDOUT, env=build_env(endpoint)) if args.keep_going: with open(log, "w") as out: subprocess.run(["cmd", "/c", r".\cmakew --build --preset RelWithDebInfo --target OpenSHC.dll -- /K"], - stdout=out, stderr=subprocess.STDOUT, env=build_env()) + stdout=out, stderr=subprocess.STDOUT, env=build_env(endpoint)) return log.read_text(errors="replace") @@ -43,6 +51,14 @@ def run_build(): print("note: PDB server error, stopping this worktree's mspdbsrv.exe and retrying", file=sys.stderr) kill_pdb_server() text = run_build() +if PDB_ERROR_RE.search(text): + # The endpoint itself can be wedged, in which case it outlives every mspdbsrv.exe using it and + # retrying into the same name fails forever. Move to a fresh one. + endpoint = fresh_pdb_endpoint() + print("note: PDB endpoint still failing, retrying on a fresh endpoint %s" % endpoint, + file=sys.stderr) + kill_pdb_server() + text = run_build(endpoint) errors = [line for line in text.splitlines() if re.search(r" error |warning C4700|warning C4715", line) and "U1077" not in line] diff --git a/tools/reimplementation-helper/batch/common.py b/tools/reimplementation-helper/batch/common.py index 5287dbdbc..64406b95c 100644 --- a/tools/reimplementation-helper/batch/common.py +++ b/tools/reimplementation-helper/batch/common.py @@ -38,10 +38,28 @@ PDB_ERROR_RE = re.compile(r"fatal error C10(90|33)") -def build_env(): - """Environment for anything that runs cl.exe, with this worktree's PDB endpoint.""" +def fresh_pdb_endpoint(): + """A previously unused endpoint name for this worktree. + + An endpoint can wedge in a way that outlives every mspdbsrv.exe using it: the name stays + unusable, and `cl.exe` keeps failing with C1090 no matter how often the server is killed and + restarted. Six consecutive builds failed that way once, across a fresh PCH and PDBs, while the + same tree built first try under a different name. So when killing the server does not help, + move to a new name rather than retrying into the same one. + """ + return "%s_%d" % (PDB_ENDPOINT, os.getpid()) + + +def build_env(endpoint=None): + """Environment for anything that runs cl.exe, with this worktree's PDB endpoint. + + An endpoint already set in the environment wins, so a caller can pin one for a whole session. + """ env = dict(os.environ) - env.setdefault("_MSPDBSRV_ENDPOINT_", PDB_ENDPOINT) + if endpoint: + env["_MSPDBSRV_ENDPOINT_"] = endpoint + else: + env.setdefault("_MSPDBSRV_ENDPOINT_", PDB_ENDPOINT) return env From 116bd931b929c7e90016649ed9c222a1f80709a1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:05:37 +0200 Subject: [PATCH 174/252] reimplement: SHC_3BB0A8C1_0x004FC0B0 36.36% 36.36% regalloc --- .../computeTileCliffEdgeFlags.cpp | 114 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/computeTileCliffEdgeFlags.cpp diff --git a/src/OpenSHC/Map/TileMapState/computeTileCliffEdgeFlags.cpp b/src/OpenSHC/Map/TileMapState/computeTileCliffEdgeFlags.cpp new file mode 100644 index 000000000..0271b3297 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/computeTileCliffEdgeFlags.cpp @@ -0,0 +1,114 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Game/GameMode.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_RIVER; + + using OpenSHC::Game::GameMode; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FC0B0 + void TileMapState::computeTileCliffEdgeFlags(int tile, int x, int y) + { + int height = this->HeightLayer[tile]; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_MULTIPLAYER) { + return; + } + + /* the height of each of the eight neighbours, or this tile's own where there is no river */ + int heights[8]; + int lowest = height; + int highest = height; + for (int i = 0; i < 8; i++) { + uint neighbourY = y + DAT_TerrainDefinedData::instance.field2476_0x372c[i].y; + uint neighbourX = x + DAT_TerrainDefinedData::instance.field2476_0x372c[i].x; + heights[i] = height; + if (neighbourX < 400 && neighbourY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[neighbourY * 400 + neighbourX] != 0) { + int neighbour = DAT_ViewportRenderState::instance.translationMatrix[neighbourY].addXgetTile + + DAT_TerrainDefinedData::instance.field2476_0x372c[i].x + x; + if ((this->LogicLayer[neighbour] & L_RIVER) != 0) { + heights[i] = this->HeightLayer[neighbour]; + if (heights[i] < lowest) { + lowest = heights[i]; + } else if (heights[i] > highest) { + highest = heights[i]; + } + } + } + } + + this->Logic2Layer[tile] + = this->Logic2Layer[tile] & (OpenSHC::Map::LogicHelpers::L2_BEACH | OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS | OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH); + byte flags = this->Logic2Layer[tile]; + if (lowest >= height) { + /* a bank all round: low step becomes a beach, a high one a cliff */ + if (highest > height) { + if (highest <= height + 0x10) { + flags = flags | 0x80; + } else { + flags = flags | 0x40; + } + } + } else if (this->mapOrientation == 4) { + if (heights[0] >= height) { + if (heights[6] < height) { + flags = flags | 4; + } + } else if (heights[6] < height) { + flags = flags | 1; + } else { + flags = flags | 2; + } + } else { + /* the bank runs along whichever axis the map is turned to */ + int along = 0; + int across = 0; + bool turned = true; + if (this->mapOrientation == 0) { + along = heights[2]; + across = heights[4]; + } else if (this->mapOrientation == 2) { + along = heights[4]; + across = heights[6]; + } else if (this->mapOrientation == 6) { + along = heights[0]; + across = heights[2]; + } else { + turned = false; + } + if (turned) { + if (along < height) { + if (across < height) { + flags = flags | 1; + } else { + flags = flags | 4; + } + } else if (across < height) { + flags = flags | 2; + } + } + } + this->Logic2Layer[tile] = flags; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 801e59db3..99bdbacd8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41081,7 +41081,7 @@ SHC_3BB0A8C1_0x004FBD80 | 38.7% | brush step regalloc SHC_3BB0A8C1_0x004FBE70 | 87.2% | 85.48% regalloc -SHC_3BB0A8C1_0x004FC0B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FC0B0 | 36.4% | 36.36% regalloc SHC_3BB0A8C1_0x004FC280 | 85.2% | XYPair base regalloc From 3008d3b89cd199dcbf8c2c5bf41cc096e4462c2a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:05:37 +0200 Subject: [PATCH 175/252] reimplement: SHC_3BB0A8C1_0x004F6CF0 8.43% 9.04% this in esi vs ecx regal --- .../TileMapState/resetHeightAndMapBorders.cpp | 126 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/resetHeightAndMapBorders.cpp diff --git a/src/OpenSHC/Map/TileMapState/resetHeightAndMapBorders.cpp b/src/OpenSHC/Map/TileMapState/resetHeightAndMapBorders.cpp new file mode 100644 index 000000000..59da20a4a --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/resetHeightAndMapBorders.cpp @@ -0,0 +1,126 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F6CF0 + void TileMapState::resetHeightAndMapBorders(int mapSize) + { + int inset = (400 - mapSize) / 2; + this->mapSize = mapSize; + for (int tile = 0; tile < 80400; tile += 6) { + if ((this->LogicLayer[tile + 0] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 0] = this->DefaultHeightLayer[tile + 0]; + } + this->LogicLayer[tile + 0] = this->LogicLayer[tile + 0] & ~(L_BORDER | L_BORDER_EDGE); + if ((this->LogicLayer[tile + 1] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 1] = this->DefaultHeightLayer[tile + 1]; + } + this->LogicLayer[tile + 1] = this->LogicLayer[tile + 1] & ~(L_BORDER | L_BORDER_EDGE); + if ((this->LogicLayer[tile + 2] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 2] = this->DefaultHeightLayer[tile + 2]; + } + this->LogicLayer[tile + 2] = this->LogicLayer[tile + 2] & ~(L_BORDER | L_BORDER_EDGE); + if ((this->LogicLayer[tile + 3] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 3] = this->DefaultHeightLayer[tile + 3]; + } + this->LogicLayer[tile + 3] = this->LogicLayer[tile + 3] & ~(L_BORDER | L_BORDER_EDGE); + if ((this->LogicLayer[tile + 4] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 4] = this->DefaultHeightLayer[tile + 4]; + } + this->LogicLayer[tile + 4] = this->LogicLayer[tile + 4] & ~(L_BORDER | L_BORDER_EDGE); + if ((this->LogicLayer[tile + 5] & (L_BORDER | L_BORDER_EDGE)) != 0) { + this->HeightLayer[tile + 5] = this->DefaultHeightLayer[tile + 5]; + } + this->LogicLayer[tile + 5] = this->LogicLayer[tile + 5] & ~(L_BORDER | L_BORDER_EDGE); + } + + /* the two outer diagonals of the diamond carry the border flags */ + int rowStart = 0; + int rowLength = 0; + do { + this->LogicLayer[rowStart] = this->LogicLayer[rowStart] | L_BORDER; + if (rowLength > 0) { + this->LogicLayer[rowStart + 1] = this->LogicLayer[rowStart + 1] | L_BORDER_EDGE; + } + if (rowLength > 0 && (this->LogicLayer[rowStart + rowLength] & L_BORDER) == 0) { + this->LogicLayer[rowStart + rowLength] = L_BORDER_EDGE; + } + this->LogicLayer[rowStart + rowLength + 1] = L_BORDER; + rowStart = rowStart + rowLength + 2; + rowLength = rowLength + 2; + } while (rowLength < 400); + + for (rowLength = 398; rowLength > -1; rowLength = rowLength - 2) { + this->LogicLayer[rowStart] = L_BORDER; + if (rowLength > 0) { + this->LogicLayer[rowStart + 1] = L_BORDER_EDGE; + } + if (rowLength > 0 && (this->LogicLayer[rowStart + rowLength] & L_BORDER) == 0) { + this->LogicLayer[rowStart + rowLength] = L_BORDER_EDGE; + } + this->LogicLayer[rowStart + rowLength + 1] = L_BORDER; + rowStart = rowStart + rowLength + 2; + } + + /* and again inset by (400 - mapSize) / 2 for a map smaller than the full diamond */ + int tile = 0; + int row = 0; + for (int skipped = inset; skipped > 0; skipped--) { + tile = tile + 2 + row; + row = row + 2; + } + if (row < 400) { + int edge = row - inset; + do { + this->LogicLayer[tile + inset] = this->LogicLayer[tile + inset] | L_BORDER; + if (edge > 0) { + this->LogicLayer[tile + inset + 1] = this->LogicLayer[tile + inset + 1] | L_BORDER_EDGE; + } + tile = tile + 1 + row; + if (edge > 0 && (this->LogicLayer[tile - inset] & L_BORDER) == 0) { + this->LogicLayer[tile - inset - 1] = this->LogicLayer[tile - inset - 1] | L_BORDER_EDGE; + } + this->LogicLayer[tile - inset] = this->LogicLayer[tile - inset] | L_BORDER; + row = row + 2; + tile = tile + 1; + edge = edge + 2; + } while (row < 400); + } + if (row < 399) { + int edge = 0x18e - inset; + for (int back = 0x18e; row <= back; back = back - 2) { + this->LogicLayer[tile + inset] = this->LogicLayer[tile + inset] | L_BORDER; + if (edge > 0) { + this->LogicLayer[tile + inset + 1] = this->LogicLayer[tile + inset + 1] | L_BORDER_EDGE; + } + tile = tile + 1 + back; + if (edge > 0 && (this->LogicLayer[tile - inset] & L_BORDER) == 0) { + this->LogicLayer[tile - inset - 1] = this->LogicLayer[tile - inset - 1] | L_BORDER_EDGE; + } + this->LogicLayer[tile - inset] = this->LogicLayer[tile - inset] | L_BORDER; + tile = tile + 1; + edge = edge - 2; + } + } + if (mapSize != 400) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setWalkabilityBorderLogicLayerForSmallerMapSizes, + DAT_PathFindingState::ptr)(); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 99bdbacd8..895063c4b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38747,7 +38747,7 @@ SHC_3BB0A8C1_0x004F6C20 | 0.0% | Pending SHC_3BB0A8C1_0x004F6C60 | 92.3% | border index regalloc -SHC_3BB0A8C1_0x004F6CF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F6CF0 | 8.4% | 9.04% this in esi vs ecx regal SHC_3BB0A8C1_0x004F6DC0 | 0.0% | Pending From 58e1dc206190421b27794d1ad56e580dd80b5071 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:05:38 +0200 Subject: [PATCH 176/252] reimplement: SHC_3BB0A8C1_0x00508250 40.29% 39.78% regalloc --- src/OpenSHC/Map/TileMapState/placeQuarry.cpp | 137 +++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeQuarry.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeQuarry.cpp b/src/OpenSHC/Map/TileMapState/placeQuarry.cpp new file mode 100644 index 000000000..8ffcf266b --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeQuarry.cpp @@ -0,0 +1,137 @@ + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/UI/BottomLeftTextDisplayState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BottomLeftTextDisplayState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumShort": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508250 + void TileMapState::placeQuarry(int playerID, uint x, uint y, undefined4 buildingType, uint buildingSize, + int buildingOrientation, uint height) + { + uint baseY = y; + int uid = DAT_GameCore::instance.uniqueGameObjectTracker; + int quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, x, y, height, + (BuildingType)(int)(short)buildingType, buildingSize, playerID, buildingOrientation); + this->placedBuildingID = quarryID; + DAT_BuildingsState::instance.buildings[quarryID].uidWhenPlaced = uid; + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingSize); + /* the original reuses the y parameter to hold the truncated building id */ + y = (short)quarryID; + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + baseY].addXgetTile + x + this->buildingX; + index++; + this->HeightLayer[tile] = (byte)height; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)y; + this->BuildingWasLayer[tile] = (uchar)buildingType; + this->ChangedLayer[tile] = 2; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(quarryID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(quarryID); + + /* nine attempts at a pile location, moving further from the quarry each time */ + int attempt = 1; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findQuarryPileLocation, DAT_BuildingsState::ptr)( + playerID, x, baseY, buildingSize, 2, attempt, OpenSHC::Commands::M_MAPPER_QUARRYPILE); + if (this->buildingPlacementFail == FALSE) { + break; + } + attempt++; + } while (attempt < 10); + if (this->buildingPlacementFail != FALSE) { + return; + } + + int pileX = x + DAT_BuildingsState::instance.DAT_TempXOffset; + int pileY = baseY + DAT_BuildingsState::instance.DAT_TempYOffset; + buildingSize = 0; + height = 1000; + uint highest = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(buildingSize, 2); + uint tileHeight = this->HeightLayer[DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + pileY].addXgetTile + + pileX + this->buildingX]; + if (highest < tileHeight) { + highest = tileHeight; + } + if (tileHeight < height) { + height = tileHeight; + } + buildingSize = buildingSize + 1; + } while ((int)buildingSize < this->constructionTileCount); + int pileHeight = (int)(highest - height) / 2 + height; + + buildingSize = 0; + int pileID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)(playerID, pileX, pileY, + pileHeight, OpenSHC::Map::Buildings::BT_QUARRYSTOCKPILE, 2, playerID, buildingOrientation); + MACRO_CALL_MEMBER(OpenSHC::AI::AIVState_Func::incrementStructureHeatMapTile, DAT_AIVState::ptr)( + pileX, pileY); + DAT_BuildingsState::instance.buildings[pileID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[quarryID].quarryStockpileID = (short)pileID; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(buildingSize, 2); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + pileY].addXgetTile + pileX + this->buildingX; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)(tile); + this->HeightLayer[tile] = (byte)pileHeight; + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + this->BuildingLayer[tile] = (short)pileID; + buildingSize = buildingSize + 1; + this->BuildingWasLayer[tile] = (uchar)buildingType; + this->ChangedLayer[tile] = 2; + } while ((int)buildingSize < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(pileID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(pileID); + + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.playerDataArray[playerID].availablePeasantsAtFire + < DAT_BuildingsState::instance.buildings[pileID].buildingTypeBasedEmployeeCount + && (DAT_GameState::instance.playerDataArray[playerID].populationCap + <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation + || DAT_GameState::instance.playerDataArray[playerID].popularity < 5000)) { + /* "Not enough workers available to run this building." */ + MACRO_CALL_MEMBER(OpenSHC::UI::BottomLeftTextDisplayState_Func::setBottomLeftTextDisplayText, + DAT_BottomLeftTextDisplayState::ptr)( + 1, 0x4d, 1, OpenSHC::UI::TextMessageBLLookupStructUnion(), 100, 6000); + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 895063c4b..c237a6515 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42153,7 +42153,7 @@ SHC_3BB0A8C1_0x00507F80 | 0.0% | Pending SHC_3BB0A8C1_0x00508030 | 61.1% | 68.42% x/y param reuse regallo -SHC_3BB0A8C1_0x00508250 | 0.0% | Pending +SHC_3BB0A8C1_0x00508250 | 40.3% | 39.78% regalloc SHC_3BB0A8C1_0x00508540 | 52.9% | 55.63% operand order regalloc From 29bf091cbf7fd235bbfc338b2c759bdb1a1c9a53 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:05:38 +0200 Subject: [PATCH 177/252] reimplement: SHC_3BB0A8C1_0x004FFBA0 30.69% 26.79% duplicated tails regall --- .../Map/TileMapState/getTotalHeightAt.cpp | 206 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/getTotalHeightAt.cpp diff --git a/src/OpenSHC/Map/TileMapState/getTotalHeightAt.cpp b/src/OpenSHC/Map/TileMapState/getTotalHeightAt.cpp new file mode 100644 index 000000000..0d38a42e6 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/getTotalHeightAt.cpp @@ -0,0 +1,206 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FFBA0 + int TileMapState::getTotalHeightAt(int tile, int playerID) + { + uint logic = this->LogicLayer[tile]; + int extra = 0; + bool exposed = false; + int owner; + if ((logic & L_KEEP_NON_MANOR_HOUSE) != 0) { + int buildingID = this->BuildingLayer[tile]; + extra = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)(buildingID); + for (int i = 0; i < 8; i++) { + if (this->BuildingLayer[this->directionTranslationMatrix + [DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]][i] + + tile] + != buildingID) { + exposed = true; + break; + } + } + if (playerID == 0) { + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } + owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + } else if ((logic & L_BUILDING) != 0) { + int buildingID = this->BuildingLayer[tile]; + int type = (short)DAT_BuildingsState::instance.buildings[buildingID].buildingType; + switch (type) { + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + extra = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + buildingID); + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_MANORHOUSE) { + for (int i = 0; i < 8; i++) { + if (this->BuildingLayer[this->directionTranslationMatrix + [DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]][i] + + tile] + != buildingID) { + exposed = true; + break; + } + } + } + break; + case 0x2d: + case 0x2e: + extra = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + buildingID); + exposed = true; + break; + default: + extra = DAT_BuildingDefinedData::instance.BuildingHeights[type]; + break; + case 0x3d: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + extra = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + buildingID); + extra = extra + 0x14; + exposed = true; + } + if (playerID != 0 && DAT_BuildingsState::instance.buildings[buildingID].owner != playerID) { + exposed = false; + } + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } else if ((char)logic < 0 && (logic & L_WALL_OR_GATEHOUSE) == 0) { + /* L_ROCKY is read as the sign of the low byte */ + if (this->OrganismLayer[tile] > 1999) { + /* fixme: the rock table is reached through the tree array */ + short rockType = (&DAT_LandscapeState::instance.trees[1590].treeTypeBasedValue1)[this->OrganismLayer[tile] * 16]; + if (rockType < 0xd) { + if (rockType > 8) { + extra = 0x32; + } + } else { + extra = 0x46; + } + } + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } else if ((logic & L_CRENEL_VARIATIONUnk) != 0) { + extra = 0x14; + exposed = true; + if (playerID != 0 && (this->WallOwnerLayer[tile] & 7) + 1 != playerID) { + exposed = false; + } + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } else if ((logic & L_CRENEL) != 0) { + extra = 10; + exposed = true; + if (playerID == 0) { + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } + owner = (this->WallOwnerLayer[tile] & 7) + 1; + } else { + if (this->BuildingLayer[tile] == 0) { + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } + int buildingID = this->BuildingLayer[tile]; + extra = 0x1e; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL) { + /* a gatehouse only counts as cover while both of its span tiles are still standing */ + int first; + int second; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0x50) { + first = 2; + second = 6; + } else { + first = 0; + second = 4; + } + exposed = this->BuildingLayer[this->directionTranslationMatrix + [DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]][first] + + tile] + != buildingID; + if (this->BuildingLayer[this->directionTranslationMatrix + [DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]][second] + + tile] + != buildingID) { + exposed = true; + } + } + if (playerID == 0) { + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } + owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + } + + if (owner != playerID) { + exposed = false; + } + extra = extra + this->HeightLayer[tile]; + if (exposed) { + return extra; + } + return -1 - extra; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c237a6515..d8177af03 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41261,7 +41261,7 @@ SHC_3BB0A8C1_0x004FFB03 | 0.0% | Pending SHC_3BB0A8C1_0x004FFB10 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004FFBA0 | 0.0% | Pending +SHC_3BB0A8C1_0x004FFBA0 | 30.7% | 26.79% duplicated tails regall SHC_3BB0A8C1_0x004FFECC | 0.0% | Pending From c29b7dcb2b78e6dc88d90a3dd132ee0c2c8ec9fe Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:48:10 +0200 Subject: [PATCH 178/252] header: name the int at 0x5548d0 that the flat view toggle clears prepareMap and setupAllMapSections both write 0 there right after toggleFlatView(0), alongside flatViewToggleValue2, so the four bytes are a field rather than padding. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TileMapState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState.hpp b/src/OpenSHC/Map/TileMapState.hpp index 7edd3b5b5..530648c03 100644 --- a/src/OpenSHC/Map/TileMapState.hpp +++ b/src/OpenSHC/Map/TileMapState.hpp @@ -123,7 +123,7 @@ namespace Map { undefined4 refreshRelatedOne; // 0x005548C4 length: 4 undefined4 field93_0x5548c8; // 0x005548C8 length: 4 undefined4 flatViewToggleValue1; // 0x005548CC length: 4 - undefined1 padding_0x5548d0[4]; // 0x005548D0 length: 4 + undefined4 field95_0x5548d0; // 0x005548D0 length: 4 undefined4 flatViewToggleValue2; // 0x005548D4 length: 4 undefined4 refreshRelatedTwo; // 0x005548D8 length: 4 undefined4 field101_0x5548dc; // 0x005548DC length: 4 From fcc7f00d215ffe177fd0aaff732b7048edc85079 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:48:17 +0200 Subject: [PATCH 179/252] reimplement: SHC_3BB0A8C1_0x004F8BD0 44.24% 44.57% regalloc --- .../TileMapState/renderWallDragPreview.cpp | 191 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/renderWallDragPreview.cpp diff --git a/src/OpenSHC/Map/TileMapState/renderWallDragPreview.cpp b/src/OpenSHC/Map/TileMapState/renderWallDragPreview.cpp new file mode 100644 index 000000000..3d9cdd600 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/renderWallDragPreview.cpp @@ -0,0 +1,191 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F8BD0 + void TileMapState::renderWallDragPreview( + int playerID, uint x1, uint y1, uint x2, uint y2, undefined4 command) + { + int budget = 0; + if (x1 > 399 || y1 > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y1 * 400 + x1] == 0) { + return; + } + if (x2 > 399 || y2 > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y2 * 400 + x2] == 0) { + return; + } + + this->DAT_WallTileCountCurrentDrag = 0; + int overshoot = 2; + if ((short)command == 0x1b) { + budget = this->field119_0x554924; + if (this->field118_0x554920 == 0) { + this->ConstructionGFXLayer[DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile + x1] + = (short)GMTotalPicturesProcessed::instance[6] + 0x13; + return; + } + } + + /* the drag walks one tile at a time towards (x2, y2), on whichever axis is further away */ + int upY = y1 - y2; + int downY = y2 - y1; + uint x = x1; + uint y = y1; + int leftX = x1 - x2; + int rightX = x2 - x1; + int* translation = &DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; + int tile; + do { + if ((short)command == 0x1b && budget < 0x18) { + break; + } + tile = *translation + x; + if ((short)command == 0x1b && (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0) { + break; + } + if (this->constructionTileCount <= this->DAT_WallTileCountCurrentDrag) { + break; + } + + /* a crenel dragged over an existing one does not count against the tile budget */ + bool onCrenel = false; + if ((short)command == 0x19 && (this->LogicLayer[tile] & L_CRENEL) != 0) { + onCrenel = true; + } + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0 || this->DamageLayer[tile] != 0 || onCrenel) { + if (!onCrenel) { + this->DAT_WallTileCountCurrentDrag = this->DAT_WallTileCountCurrentDrag + 1; + } + if (this->illegalBuild == FALSE) { + if ((short)command == 0x19) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6]; + } else if ((short)command == 0x2e) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 1; + } else if ((short)command == 0x1a) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 4; + } else if ((short)command == 0x1b) { + /* a stair climbs one graphic per eight units of height below the wall top */ + int steps = (budget - (int)(uint)this->HeightLayer[tile]) / 8 - 1; + if (steps > 0) { + if (steps > 10) { + steps = 10; + } + this->ConstructionGFXLayer[tile] = (short)steps + 8 + (ushort)GMTotalPicturesProcessed::instance[6]; + } else { + this->DAT_WallTileCountCurrentDrag = this->DAT_WallTileCountCurrentDrag - 1; + } + } + } else if ((short)command == 0x19) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 0x13; + } else if ((short)command == 0x2e) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 0x13; + } else if ((short)command == 0x1a) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 0x14; + } else if ((short)command == 0x1b) { + this->ConstructionGFXLayer[tile] = (ushort)GMTotalPicturesProcessed::instance[6] + 0x13; + } + } + + int stepX = leftX; + if ((int)x < (int)x2) { + stepX = rightX; + } + int stepY = upY; + if ((int)y < (int)y2) { + stepY = downY; + } + if ((short)command == 0x1b) { + if (stepY < stepX) { + if ((int)x < (int)x2) { + leftX = leftX + 1; + x = x + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + x = x - 1; + rightX = rightX + 1; + } + } else if (stepY > 0) { + if ((int)y < (int)y2) { + translation = translation + 3; + y = y + 1; + upY = upY + 1; + downY = downY - 1; + } else { + translation = translation - 3; + y = y - 1; + upY = upY - 1; + downY = downY + 1; + } + } else { + overshoot = overshoot - 1; + } + } else { + if (stepX != 0) { + if ((int)x < (int)x2) { + leftX = leftX + 1; + x = x + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + x = x - 1; + rightX = rightX + 1; + } + } + if (stepY != 0) { + if ((int)y < (int)y2) { + translation = translation + 3; + y = y + 1; + upY = upY + 1; + downY = downY - 1; + } else { + translation = translation - 3; + y = y - 1; + upY = upY - 1; + downY = downY + 1; + } + } + if (x == x2 && y == y2) { + overshoot = overshoot - 1; + } + } + if (budget > 0x10 && overshoot == 2) { + budget = budget - 0x10; + } + } while (x != x2 || y != y2 || overshoot != 0); + + if (this->illegalBuild != FALSE) { + this->DAT_WallTileCountCurrentDrag = 0; + } + if (this->field145_0x554980 != 0) { + return; + } + if ((short)command == 0x2e) { + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processWallBuildingLoss, DAT_BuildingsState::ptr)( + playerID, 0, this->DAT_WallTileCountCurrentDrag, 1); + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processWallBuildingLoss, DAT_BuildingsState::ptr)( + playerID, this->DAT_WallTileCountCurrentDrag, 0, 1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d8177af03..3424be4d0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39377,7 +39377,7 @@ SHC_3BB0A8C1_0x004F8AC0 | 90.7% | shr vs sar on logic bit SHC_3BB0A8C1_0x004F8B50 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F8BD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F8BD0 | 44.2% | 44.57% regalloc SHC_3BB0A8C1_0x004F9000 | 59.5% | owner store tail-merge From 44c4613b9c85c302bc6da0eae2b99e407bfa3ab3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:48:17 +0200 Subject: [PATCH 180/252] reimplement: SHC_3BB0A8C1_0x004F9590 23.63% 24.13% index arithmetic regall --- ...ingSizeIndexMappingForBuildingWithSize.cpp | 156 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMappingForBuildingWithSize.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMappingForBuildingWithSize.cpp b/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMappingForBuildingWithSize.cpp new file mode 100644 index 000000000..21bfd67c9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupBuildingSizeIndexMappingForBuildingWithSize.cpp @@ -0,0 +1,156 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingSizeIndexMapping.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9590 + void TileMapState::setupBuildingSizeIndexMappingForBuildingWithSize(int buildingSize) + { + int size = buildingSize; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 4056, '\0', DAT_BuildingSizeIndexMapping::instance + buildingSize); + int last = buildingSize * buildingSize + -1; + if (buildingSize <= 1) { + return; + } + + /* pass 0: the unrotated footprint, in reading order */ + for (int y = 0; y < buildingSize; y++) { + for (int x = 0; x < buildingSize; x++) { + DAT_BuildingSizeIndexMapping::instance[buildingSize][y * buildingSize + x][0] = x; + DAT_BuildingSizeIndexMapping::instance[buildingSize][y * buildingSize + x][1] = y; + } + } + + int diagonals = buildingSize * 2 + -1; + + /* passes 1 to 4: the same tiles walked diagonally, one pass per rotation */ + int column = 0; + int base = 0; + int run = 1; + int index = last; + for (int diagonal = 0; diagonal < diagonals; diagonal++) { + for (int step = 0; step < run; step++) { + if (step == 0) { + base = (base + 169) * buildingSize; + } + DAT_BuildingSizeIndexMapping::instance[0][base + column][2] = index; + index = index + -1; + if (step < run + -1) { + column = column + -1; + base = base + buildingSize; + } + } + column = buildingSize + -1; + if (diagonal < column) { + run = run + 1; + column = diagonal + 1; + base = 0; + } else { + run = run + -1; + base = (1 - (buildingSize + -1)) + diagonal; + } + } + + int row = buildingSize + -1; + base = 0; + run = 1; + index = last; + int mirror = buildingSize * 2 + -3; + for (int diagonal = 0; diagonal < diagonals; diagonal++) { + for (int step = 0; step < run; step++) { + if (step == 0) { + base = (base + 0xa9) * buildingSize; + } + DAT_BuildingSizeIndexMapping::instance[0][base + row][3] = index; + index = index + -1; + if (step < run + -1) { + row = row + -1; + base = base - buildingSize; + } + } + row = buildingSize + -1; + if (diagonal < row) { + run = run + 1; + base = diagonal + 1; + } else { + run = run + -1; + base = row; + row = mirror; + } + mirror = mirror + -1; + } + + base = buildingSize + -1; + run = 1; + index = last; + mirror = buildingSize + -2; + column = base; + for (int diagonal = 0; diagonal < diagonals; diagonal++) { + for (int step = 0; step < run; step++) { + if (step == 0) { + base = (base + 0xa9) * buildingSize; + } + DAT_BuildingSizeIndexMapping::instance[0][base + column][4] = index; + index = index + -1; + if (step < run + -1) { + column = column + 1; + base = base - buildingSize; + } + } + base = buildingSize + -1; + if (diagonal < base) { + run = run + 1; + column = mirror; + } else { + run = run + -1; + column = 0; + base = mirror + base; + } + mirror = mirror + -1; + } + + base = buildingSize + -1; + column = 0; + run = 1; + index = last; + int shrink = buildingSize + -2; + int offset = 1 - base; + for (int diagonal = 0; diagonal < size * 2 + -1; diagonal++) { + for (int step = 0; step < run; step++) { + if (step == 0) { + base = (base + 0xa9) * size; + } + DAT_BuildingSizeIndexMapping::instance[0][base + column][5] = index; + index = index + -1; + if (step < run + -1) { + column = column + 1; + base = base + size; + } + } + if (diagonal < size + -1) { + run = run + 1; + column = 0; + base = shrink; + } else { + run = run + -1; + column = offset + diagonal; + base = 0; + } + shrink = shrink + -1; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3424be4d0..71c60fadd 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39387,7 +39387,7 @@ SHC_3BB0A8C1_0x004F93E0 | 49.0% | const 1 rematerialised SHC_3BB0A8C1_0x004F94A0 | 67.2% | logic masks merged by cl -SHC_3BB0A8C1_0x004F9590 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9590 | 23.6% | 24.13% index arithmetic regall SHC_3BB0A8C1_0x004F9630 | 0.0% | Pending From 3f9dd9bc0ca9f52130fbad3d5a7044d5fe2ee1b6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:48:17 +0200 Subject: [PATCH 181/252] reimplement: SHC_3BB0A8C1_0x00512100 70.70% 87.94% call targets only --- .../Map/TileMapState/setupAllMapSections.cpp | 163 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setupAllMapSections.cpp diff --git a/src/OpenSHC/Map/TileMapState/setupAllMapSections.cpp b/src/OpenSHC/Map/TileMapState/setupAllMapSections.cpp new file mode 100644 index 000000000..3228fe8ea --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setupAllMapSections.cpp @@ -0,0 +1,163 @@ + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AICState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WallAndPitchState.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00512100 + void TileMapState::setupAllMapSections() + { + this->temporaryTerrainTypeIndex = 0; + this->SEC_Section1052 = 0; + this->SEC_Section1053 = 0; + this->SEC_Section1054 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupTileMapSections, this)(); + DAT_WallAndPitchState::instance.countdown = 0; + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::setTileSystemMemoryLookupArrays, DAT_ViewportRenderState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::tweakValidTilesToExcludeMapBorders, DAT_ViewportRenderState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::setupViewport, DAT_ViewportRenderState::ptr)(0, 0, + DAT_WindowAndDirectDraw::instance.resolutionX, DAT_WindowAndDirectDraw::instance.resolutionY - 128); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setupLogicalMapBorders, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateShowHiLayerOrResetChangedLayer, this)(); + + /* the border tiles get their own graphic, everything else the plain one */ + for (int tile = 0; tile < 80400; tile += 6) { + if (this->LogicLayer[tile + 0] == L_BORDER) { + this->GfxLayer[tile + 0] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 0] == L_BORDER_EDGE) { + this->GfxLayer[tile + 0] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 0] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + if (this->LogicLayer[tile + 1] == L_BORDER) { + this->GfxLayer[tile + 1] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 1] == L_BORDER_EDGE) { + this->GfxLayer[tile + 1] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 1] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + if (this->LogicLayer[tile + 2] == L_BORDER) { + this->GfxLayer[tile + 2] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 2] == L_BORDER_EDGE) { + this->GfxLayer[tile + 2] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 2] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + if (this->LogicLayer[tile + 3] == L_BORDER) { + this->GfxLayer[tile + 3] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 3] == L_BORDER_EDGE) { + this->GfxLayer[tile + 3] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 3] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + if (this->LogicLayer[tile + 4] == L_BORDER) { + this->GfxLayer[tile + 4] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 4] == L_BORDER_EDGE) { + this->GfxLayer[tile + 4] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 4] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + if (this->LogicLayer[tile + 5] == L_BORDER) { + this->GfxLayer[tile + 5] = (ushort)GMTotalPicturesProcessed::instance[2]; + } else if (this->LogicLayer[tile + 5] == L_BORDER_EDGE) { + this->GfxLayer[tile + 5] = (ushort)GMTotalPicturesProcessed::instance[2] + 1; + } else { + this->GfxLayer[tile + 5] = (ushort)GMTotalPicturesProcessed::instance[2] + 2; + } + } + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ShortValue, DAT_LowLevelMemory::ptr)(80400, 1, this->PillarGFXLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(80400, '\b', this->HeightLayer); + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\b', this->DefaultHeightLayer); + DAT_PathFindingState::instance.searchGeneration = 1; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(160800, '\0', this->WalkLayer); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setChangedLayerZeroBasedOn40x40Layer, DAT_PathFindingState::ptr)(0); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateLogicalTileMapRelatedSections, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateGfxLayer, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updateGFXLayers, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetMoatArray, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetPitchDitchArray, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::toggleFlatView, this)(0); + this->field95_0x5548d0 = 0; + this->flatViewToggleValue2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::clearBuildings, DAT_BuildingsState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::clearRocksAndTrees, DAT_LandscapeState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::resetWind, DAT_LandscapeState::ptr)(); + MACRO_CALL(OpenSHC::Global_Func::DoNothing)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::clearAllUnits, DAT_UnitsState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::clearAllTribes, DAT_TribesState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::clearMapAndTimeAndPlayerData, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::resetVariousCountsAndStatisticsAndStartGoodsAndResources, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::clearCurrentResourcesAndStrongWalls, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::initializeGameStateAfterMapLoad, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::fillWith0xFF, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::clearAnimalSpawnLocationsUnk, DAT_TribesState::ptr)(); + + for (int tribe = 0; tribe < 1000; tribe++) { + DAT_AICState::instance.tribeIDArray[tribe] = 0; + DAT_AICState::instance.tribeUIDArray[tribe] = 0; + } + MACRO_CALL(OpenSHC::Global_Func::DoNothing)(); + MACRO_CALL(OpenSHC::Global_Func::DoNothing)(); + MACRO_CALL_MEMBER( + OpenSHC::Map::Entities::EntityState_Func::clearEntityArrayAndSeagullArray, DAT_EntityState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setChangedLayerToThreeAndMapping0x40x40, this)(); + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + this->forceUpdateTextureTilemap = 1; + this->forceUpdateGFXLayers = 1; + this->forceUpdateMacroLayerFlag = 1; + this->field68_0x55487c = 200; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageLayerForEachBuildingAtEachTile, DAT_PathFindingState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateSeparateAreaTileMap, DAT_PathFindingState::ptr)(1); + this->forceUpdateMacroLayerFlag = 1; + this->field68_0x55487c = 500; + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::setTileColorsDependingOnMapSize, DAT_MinimapViewState::ptr)(0, 100); + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::setMapPropertyDependingOnMapSize, DAT_MinimapViewState::ptr)(0, 100); + DAT_GameCore::instance.currentlyInGameUnk_0xa4 = FALSE; + MACRO_CALL(OpenSHC::Map_Func::ResetSomeValuesFunctionUnk)(); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 71c60fadd..35dfa6639 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44729,7 +44729,7 @@ SHC_3BB0A8C1_0x00511DF0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x005120C0 | 0.0% | Pending -SHC_3BB0A8C1_0x00512100 | 0.0% | Pending +SHC_3BB0A8C1_0x00512100 | 70.7% | 87.94% call targets only SHC_3BB0A8C1_0x00512180 | 0.0% | Pending From 81e33d225c6f121e4dde9388450873626dd89fbc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 16:48:18 +0200 Subject: [PATCH 182/252] reimplement: SHC_3BB0A8C1_0x00512450 47.42% 80.32% call targets only --- src/OpenSHC/Map/TileMapState/prepareMap.cpp | 183 ++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/prepareMap.cpp diff --git a/src/OpenSHC/Map/TileMapState/prepareMap.cpp b/src/OpenSHC/Map/TileMapState/prepareMap.cpp new file mode 100644 index 000000000..ca7668357 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/prepareMap.cpp @@ -0,0 +1,183 @@ + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/MapPropertiesState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/WildlifeState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Text/UserTextHandler.func.hpp" +#include "OpenSHC/UI/HoveredState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_HoveredState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_MapPropertiesState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WallAndPitchState.hpp" +#include "OpenSHC/Globals/DAT_WildlifeState.hpp" +#include "OpenSHC/Globals/FilePackagerObj.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumShort": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00512450 + void TileMapState::prepareMap() + { + int savedY = DAT_ViewportRenderState::instance.viewportState.viewportY; + int savedX = DAT_ViewportRenderState::instance.viewportState.viewportX; + if (DAT_GameSynchronyState::instance.currentGameModeCopy_SEC_Section1106 == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER) { + DAT_GameSynchronyState::instance.currentGameMode = OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER; + DAT_GameSynchronyState::instance.isHost = TRUE; + char* name = MACRO_CALL_MEMBER( + OpenSHC::Text::UserTextHandler_Func::getTextArrayPointer, DAT_UserTextHandlerState::ptr)(0); + /* the human player's name goes into slot 1, terminator included */ + int i = 0; + do { + DAT_GameSynchronyState::instance.DAT_PlayerNames[1][i] = name[i]; + i++; + } while (name[i - 1] != '\0'); + MACRO_CALL_MEMBER(OpenSHC::AI::AIVState_Func::syncAIPlayerNamesAndBuildIntervals, DAT_AIVState::ptr)(); + DAT_GameSynchronyState::instance.currentPlayerSlotID = 1; + } else if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION) { + if (DAT_GameCore::instance.missionNumber1to20 < 16) { + DAT_GameSynchronyState::instance.currentGameMode = OpenSHC::Game::GM_SOLITARY; + } + } else if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_BUILDERUnk) { + DAT_GameSynchronyState::instance.currentGameMode = OpenSHC::Game::GM_SOLITARY; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::changeMapOrientation, this)(this->mapOrientation); + DAT_PathFindingState::instance.searchGeneration = 1; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)(0x27420, '\0', this->WalkLayer); + DAT_ViewportRenderState::instance.viewportState.viewportX = savedX; + DAT_ViewportRenderState::instance.viewportState.viewportY = savedY; + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::setViewportBasedOnMapSize, DAT_ViewportRenderState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::setTileSystemMemoryLookupArrays, DAT_ViewportRenderState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::tweakValidTilesToExcludeMapBorders, DAT_ViewportRenderState::ptr)(); + DAT_BuildingsState::instance.maxBuildingsCount = 2000; + DAT_UnitsState::instance.maxUnitCount = 2500; + DAT_PathFindingState::instance.maxClimbDataCount = 200; + DAT_EntityState::instance.maxEntityCount = 3000; + this->currentMoatCount = 16000; + DAT_LandscapeState::instance.maxTreeCount = 2000; + this->maxPitchDitchCount = 4000; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetHeightAndMapBorders, this)(this->mapSize); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::toggleFlatView, this)(0); + this->field95_0x5548d0 = 0; + this->flatViewToggleValue2 = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setChangedLayerToThreeAndMapping0x40x40, this)(); + this->forceUpdateLogicalAndMiscDisplayLayers = 1; + this->forceUpdateTextureTilemap = 1; + this->forceUpdateGFXLayers = 1; + this->forceUpdateMacroLayerFlag = 1; + this->field68_0x55487c = 500; + + /* every subsystem gets a chance to migrate what it loaded from an older map format */ + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::upgradeTribeArrayLayoutForMapVersion, + DAT_TribesState::ptr)((PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::uselessFunction, DAT_TroopValueState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::upgradeMapFormatForUnits, DAT_UnitsState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::upgradeMapFormatLogicLayer, this)((PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::upgradeBuildingsForMapVersion, DAT_BuildingsState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::upgradeTreesAndRocksForMapVersion, DAT_LandscapeState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::upgradeMapTribesState, DAT_TribesState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::migrateGameStateForMapVersion, DAT_GameState::ptr)((PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::handleMapVersionUpgrade, DAT_EntityState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::recountTotalOwnedMoats, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkageLayerForEachBuildingAtEachTile, DAT_PathFindingState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateSeparateAreaTileMap, DAT_PathFindingState::ptr)(1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::updatePathLinkageLayerForAllBuildings, DAT_BuildingsState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateClimbData, DAT_PathFindingState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::clearBuildingValueWhenStateIsTwo, DAT_BuildingsState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::setCurrentTimeOnSomeTrees, DAT_LandscapeState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::resetWind, DAT_LandscapeState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::collectCliffEdgeTilesForClimbData, this)(); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearInvalidMoatEntries, this)(); + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::initializeGameStateAfterMapLoad, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::MapPropertiesState_Func::sortEventsByDate, DAT_MapPropertiesState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::applyVersionUpgradeAccessibilityRecompute, DAT_BuildingsState::ptr)( + (PackagedFileMagicNum)(int)FilePackagerObj::instance.versionNumOfCurrentFileTypeUnk, + (PackagedFileMagicNum)(int)FilePackagerObj::instance.packagerMapVersionNumUnk); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateSeparateAreaTileMap, DAT_PathFindingState::ptr)(1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::updatePathLinkageLayerForAllBuildings, DAT_BuildingsState::ptr)(); + + for (int grid = 0; grid < 40; grid++) { + MACRO_CALL_MEMBER(OpenSHC::Map::WildlifeState_Func::updateWildlifeGrid, DAT_WildlifeState::ptr)(grid); + } + MACRO_CALL_MEMBER(OpenSHC::Map::WildlifeState_Func::updateWildlife, DAT_WildlifeState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::WildlifeState_Func::updateSection1034Info, DAT_WildlifeState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::WildlifeState_Func::updateNofFpoints, DAT_WildlifeState::ptr)(); + MACRO_CALL(OpenSHC::Map_Func::ResetSomeValuesFunctionUnk)(); + DAT_WallAndPitchState::instance.countdown = 0; + MACRO_CALL_MEMBER(OpenSHC::UI::HoveredState_Func::clearHoveredState, DAT_HoveredState::ptr)(); + DAT_GameCore::instance.gamePausedLogical = 0xffffffff; + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::processGameTick, DAT_GameState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateSeparateAreaTileMap, DAT_PathFindingState::ptr)(1); + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::setTileColorsDependingOnMapSize, DAT_MinimapViewState::ptr)(0, 100); + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::setMapPropertyDependingOnMapSize, DAT_MinimapViewState::ptr)(0, 100); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 35dfa6639..b3102095a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44733,7 +44733,7 @@ SHC_3BB0A8C1_0x00512100 | 70.7% | 87.94% call targets only SHC_3BB0A8C1_0x00512180 | 0.0% | Pending -SHC_3BB0A8C1_0x00512450 | 0.0% | Pending +SHC_3BB0A8C1_0x00512450 | 47.4% | 80.32% call targets only SHC_3BB0A8C1_0x005127B0 | 100.0% | Reimplemented From 499ee1142561be4b8d416f724f3e9bebe4341adf Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 18:04:14 +0200 Subject: [PATCH 183/252] tools/batch: give syntax_check.py the same PDB retries as build_quiet.py A C1090 here is worse than in a build: the fatal line is counted as an error against whichever file happened to hit it, and the files after it in the batch still get checked, so the run prints a plausible-looking error list that hides the real compile errors. It masked a C2039 twice today. Same two stages build_quiet.py uses: stop this worktree mspdbsrv.exe, then move to a fresh endpoint name. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- .../batch/syntax_check.py | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tools/reimplementation-helper/batch/syntax_check.py b/tools/reimplementation-helper/batch/syntax_check.py index 4f7212a9f..e67df175d 100644 --- a/tools/reimplementation-helper/batch/syntax_check.py +++ b/tools/reimplementation-helper/batch/syntax_check.py @@ -4,6 +4,12 @@ Needs build-RelWithDebInfo/compile_commands.json from a previous configure. Files are checked serially: runs sharing the PCH/pdb in parallel give bogus errors. + +cl.exe runs with this worktree's own _MSPDBSRV_ENDPOINT_ (see common.build_env). A run that dies +with C1090/C1033 gets the same two retries build_quiet.py takes - stop this worktree's mspdbsrv.exe, +then move to a fresh endpoint name. A PDB error matters more here than in a build: it is counted as +an error against whichever file happened to hit it, and the files after it in the batch are still +checked, so the run reports a plausible-looking error list that hides the real compile errors. """ import json @@ -12,7 +18,8 @@ import subprocess import sys -from common import BUILD_DIR, ROOT, TMP, build_env, list_files +from common import (BUILD_DIR, PDB_ERROR_RE, ROOT, TMP, build_env, fresh_pdb_endpoint, + kill_pdb_server, list_files) commands = json.loads((BUILD_DIR / "compile_commands.json").read_text()) template = next(c["command"] for c in commands if "OpenSHC.dll.dir" in c["command"]) @@ -30,9 +37,25 @@ bat = TMP / "syntax_check.bat" bat.write_text("\n".join(lines) + "\n") -result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True, - env=build_env()) -errors = [l for l in (result.stdout + result.stderr).splitlines() if " error " in l or "fatal" in l] + +def run_check(endpoint=None): + result = subprocess.run(["cmd", "/c", str(bat.resolve())], capture_output=True, text=True, + env=build_env(endpoint)) + return result.stdout + result.stderr + + +output = run_check() +if PDB_ERROR_RE.search(output): + print("note: PDB server error, stopping this worktree's mspdbsrv.exe and retrying", file=sys.stderr) + kill_pdb_server() + output = run_check() +if PDB_ERROR_RE.search(output): + endpoint = fresh_pdb_endpoint() + print("note: PDB endpoint still failing, retrying on a fresh endpoint %s" % endpoint, file=sys.stderr) + kill_pdb_server() + output = run_check(endpoint) + +errors = [l for l in output.splitlines() if " error " in l or "fatal" in l] for line in errors: print(re.sub(r"^.*src.OpenSHC.", "", line)[:260]) print("ERRORS", len(errors), "files", len(files)) From 65e1f408a1ec9184ab5ed30c6f739b3c4113fde3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:28:14 +0200 Subject: [PATCH 184/252] reimplement: SHC_3BB0A8C1_0x00508A00 71.41% 71.43% jump table, gfx select --- .../renderPreviewMapperWithBrush.cpp | 198 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/renderPreviewMapperWithBrush.cpp diff --git a/src/OpenSHC/Map/TileMapState/renderPreviewMapperWithBrush.cpp b/src/OpenSHC/Map/TileMapState/renderPreviewMapperWithBrush.cpp new file mode 100644 index 000000000..c8ec200be --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/renderPreviewMapperWithBrush.cpp @@ -0,0 +1,198 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + whenever terrain is selected and you try to place it decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00508A00 + void TileMapState::renderPreviewMapperWithBrush(uint x, uint y, MappersEnum mapper) + { + if (x > 399) { + return; + } + if (y > 399) { + return; + } + if (DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + return; + } + + int brushSize = DAT_TerrainDefinedData::instance.BrushSizeArray[this->editorActiveBrush]; + int baseTile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + if (mapper == OpenSHC::Commands::M_MAPPER_POND1 || mapper == OpenSHC::Commands::M_MAPPER_POND2_SMALL + || mapper == OpenSHC::Commands::M_MAPPER_POND3_LARGE1 || mapper == OpenSHC::Commands::M_MAPPER_POND4_LARGE2) { + this->buildingPlacementFail = FALSE; + return; + } + this->buildingPlacementFail = TRUE; + if (mapper == OpenSHC::Commands::M_MAPPER_SIGNPOST) { + return; + } + + /* every mapper draws its own preview colour */ + ushort gfx; + if ((int)mapper > OpenSHC::Commands::M_MAPPER_DUNES) { + gfx = 0x38; + } else if (mapper == OpenSHC::Commands::M_MAPPER_DUNES) { + gfx = 0x3c; + } else { + switch (mapper) { + case OpenSHC::Commands::M_MAPPER_SEA: + case OpenSHC::Commands::M_MAPPER_SHALLOWS: + case OpenSHC::Commands::M_MAPPER_RIVER: + case OpenSHC::Commands::M_MAPPER_MARSH: + case OpenSHC::Commands::M_MAPPER_DUGMOAT: + case OpenSHC::Commands::M_MAPPER_MOAT: + gfx = 0x39; + break; + case OpenSHC::Commands::M_MAPPER_SCRUB: + case OpenSHC::Commands::M_MAPPER_DIRT: + gfx = 0x3c; + break; + case OpenSHC::Commands::M_MAPPER_BEACH: + case OpenSHC::Commands::M_MAPPER_FORD: + gfx = 0x3a; + break; + case OpenSHC::Commands::M_MAPPER_ROCKY: + case OpenSHC::Commands::M_MAPPER_STONES: + case OpenSHC::Commands::M_MAPPER_BOULDERS: + case OpenSHC::Commands::M_MAPPER_PEBBLES: + case OpenSHC::Commands::M_MAPPER_IRON: + gfx = 0x3b; + break; + case OpenSHC::Commands::M_MAPPER_CHESTNUT: + case OpenSHC::Commands::M_MAPPER_OAK: + case OpenSHC::Commands::M_MAPPER_PINE: + case OpenSHC::Commands::M_MAPPER_BIRCH: + case OpenSHC::Commands::M_MAPPER_SHRUB1A: + case OpenSHC::Commands::M_MAPPER_SHRUB1B: + case OpenSHC::Commands::M_MAPPER_SHRUB1C: + case OpenSHC::Commands::M_MAPPER_SHRUB1D: + case OpenSHC::Commands::M_MAPPER_SHRUB1E: + case OpenSHC::Commands::M_MAPPER_SHRUB2A: + case OpenSHC::Commands::M_MAPPER_SHRUB2B: + case OpenSHC::Commands::M_MAPPER_SHRUB2C: + case OpenSHC::Commands::M_MAPPER_SHRUB2D: + case OpenSHC::Commands::M_MAPPER_SHRUB2E: + case OpenSHC::Commands::M_MAPPER_SHRUB3A: + case OpenSHC::Commands::M_MAPPER_SHRUB3B: + case OpenSHC::Commands::M_MAPPER_SHRUB3C: + case OpenSHC::Commands::M_MAPPER_SHRUB3D: + case OpenSHC::Commands::M_MAPPER_DEER: + case OpenSHC::Commands::M_MAPPER_LION: + case OpenSHC::Commands::M_MAPPER_RABBIT: + case OpenSHC::Commands::M_MAPPER_CAMEL: + case OpenSHC::Commands::M_MAPPER_CROW_SEAGULL: + case OpenSHC::Commands::M_MAPPER_SEAGULL: + /* a single organism is placed on one tile, whatever the brush size */ + brushSize = 1; + case OpenSHC::Commands::M_MAPPER_RAISE: + case OpenSHC::Commands::M_MAPPER_LOWER: + case OpenSHC::Commands::M_MAPPER_EQUALISE: + case OpenSHC::Commands::M_MAPPER_MOUNTAIN: + case OpenSHC::Commands::M_MAPPER_HILL: + case OpenSHC::Commands::M_MAPPER_DELETE: + gfx = 0x3e; + break; + case OpenSHC::Commands::M_MAPPER_UNDUGMOAT: + case OpenSHC::Commands::M_MAPPER_OIL: + gfx = 0x3d; + break; + default: + gfx = 0x38; + } + } + + switch (mapper) { + case OpenSHC::Commands::M_MAPPER_UNDUGMOAT: + case OpenSHC::Commands::M_MAPPER_DUGMOAT: + case OpenSHC::Commands::M_MAPPER_MOAT: + case OpenSHC::Commands::M_MAPPER_ANTIMOAT: + /* a moat may not be dug too near an enemy, a signpost, or an opponent's buildings */ + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT) { + int enemyRange; + int searchRange; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + enemyRange = 0x1e; + searchRange = 30; + } else { + enemyRange = 0xf; + searchRange = 7; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, DAT_PathFindingState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID, x, y, enemyRange) + != FALSE) { + gfx = 0x3e; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isSignPostWithinDistance, DAT_PathFindingState::ptr)( + x, y, DAT_GameState::instance.mapAndTime.unk_signpostDistance + 5) + != FALSE) { + gfx = 0x3e; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + int buildRange = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getCastleBuildRangeForMapSize, this)(); + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, DAT_PathFindingState::ptr)( + DAT_GameSynchronyState::instance.currentPlayerSlotID, x, y, searchRange, -1, -1, buildRange + 5) + != 0) { + gfx = 0x3e; + } + } + } + } + + int tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + uint brushY = y; + if (mapper == OpenSHC::Commands::M_MAPPER_DUGMOAT || mapper == OpenSHC::Commands::M_MAPPER_UNDUGMOAT + || mapper == OpenSHC::Commands::M_MAPPER_MOAT || mapper == OpenSHC::Commands::M_MAPPER_ANTIMOAT) { + /* a moat preview always covers the nine tiles around the cursor */ + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(0, index, &tile, (int*)&brushY, baseTile, y); + index++; + this->ConstructionGFXLayer[tile] = gfx; + } while (index < 9); + return; + } + if (brushSize < 1) { + return; + } + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)(1, index, &tile, (int*)&brushY, baseTile, y); + index++; + this->ConstructionGFXLayer[tile] = gfx; + } while (index < brushSize); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b3102095a..baa6fee4a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42165,7 +42165,7 @@ SHC_3BB0A8C1_0x00508870 | 88.9% | Style pass, asm differs SHC_3BB0A8C1_0x00508910 | 66.7% | ecx not kept across callee -SHC_3BB0A8C1_0x00508A00 | 0.0% | Pending +SHC_3BB0A8C1_0x00508A00 | 71.4% | 71.43% jump table, gfx select SHC_3BB0A8C1_0x00508C7C | 0.0% | Pending From 3564902471d5157bc8c724159e2279da0a9c3fc8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:28:14 +0200 Subject: [PATCH 185/252] reimplement: SHC_3BB0A8C1_0x00504A30 48.92% 48.92% global instance base --- .../evaluateBuildingPlacementAtCursor.cpp | 226 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/evaluateBuildingPlacementAtCursor.cpp diff --git a/src/OpenSHC/Map/TileMapState/evaluateBuildingPlacementAtCursor.cpp b/src/OpenSHC/Map/TileMapState/evaluateBuildingPlacementAtCursor.cpp new file mode 100644 index 000000000..0513ba5f3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/evaluateBuildingPlacementAtCursor.cpp @@ -0,0 +1,226 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingFailReasonEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingFailReasonEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00504A30 + void TileMapState::evaluateBuildingPlacementAtCursor(int playerID, uint x, uint y) + { + uint anchorX = x; + int moatTile = 0; + if (y > 399 || x > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + this->buildingPlacementFail = TRUE; + return; + } + this->buildingPlacementFail = FALSE; + if (DAT_ViewportRenderState::instance.viewportState.field15_0x3c != 0) { + moatTile = DAT_ViewportRenderState::instance.viewportState.field24_0x60; + this->field153_0x5549a0 = DAT_ViewportRenderState::instance.viewportState.field24_0x60; + } + + /* the flat view has no ray hit, so the tile under the mouse is used directly */ + uint buildingID; + int wallTile = DAT_ViewportRenderState::instance.viewportState.field21_0x54; + if (this->flatViewToggleValue1 == 0) { + buildingID = DAT_ViewportRenderState::instance.viewportState.mouseRayBuildingID; + } else { + buildingID = this->BuildingLayer[DAT_ViewportRenderState::instance.viewportState.mouseTile]; + wallTile = 0; + if ((this->LogicLayer[DAT_ViewportRenderState::instance.viewportState.mouseTile] & L_WALL_OR_GATEHOUSE) != 0 + && ((this->LogicLayer[DAT_ViewportRenderState::instance.viewportState.mouseTile] & L_STOCKPILEUnk) == 0 || buildingID == 0)) { + DAT_ViewportRenderState::instance.viewportState.field21_0x54 = DAT_ViewportRenderState::instance.viewportState.mouseTile; + wallTile = DAT_ViewportRenderState::instance.viewportState.mouseTile; + } + } + if (buildingID != 0) { + anchorX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + y = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + } + + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, DAT_PathFindingState::ptr)(playerID, anchorX, y, + (-(uint)(DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) & 0xfffffff1) + 0x1e) + != FALSE) { + this->field194_0x554a20 = 1; + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x14; + if (buildingID != 0) { + if (DAT_BuildingsState::instance.buildings[buildingID].owner == playerID || playerID == 0) { + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x14; + this->field194_0x554a20 = 1; + return; + } + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_DEFAULT_CANT_PLACE_THAT_THERE; + return; + } + if (wallTile > 0) { + if ((this->LogicLayer[wallTile] & L_WALL_OR_GATEHOUSE) == 0 + || (this->WallOwnerLayer[wallTile] & 7) + 1 == playerID) { + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x14; + this->field194_0x554a20 = 1; + return; + } + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_DEFAULT_CANT_PLACE_THAT_THERE; + return; + } + if (moatTile > 0 && (this->LogicLayer[moatTile] & L_MOAT) != 0) { + int moatID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(moatTile); + if (moatID == 0) { + return; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[this->moats[moatID].owner] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + return; + } + } + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_DEFAULT_CANT_PLACE_THAT_THERE; + return; + } + + if (DAT_ViewportRenderState::instance.viewportState.somePitchDitchID != 0) { + if (this->pitchDitches[DAT_ViewportRenderState::instance.viewportState.somePitchDitchID].owner != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + this->buildingPlacementFail = TRUE; + return; + } + this->field131_0x554954 = -DAT_ViewportRenderState::instance.viewportState.somePitchDitchID; + return; + } + + if ((int)buildingID < 1 + || (DAT_BuildingsState::instance.buildings[buildingID].owner != playerID && playerID != 0)) { + this->buildingPlacementFail = TRUE; + } + + bool checkMoat = true; + if (wallTile > 0) { + /* a stockpile tile carries the wall flag too, but nothing may be built on it */ + if ((this->LogicLayer[wallTile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[wallTile] & L_STOCKPILEUnk) != 0) { + this->buildingPlacementFail = TRUE; + return; + } + if ((this->LogicLayer[wallTile] & L_WALL_OR_GATEHOUSE) != 0 && this->BuildingLayer[wallTile] == 0 + && this->field152_0x55499c == 0) { + if ((this->WallOwnerLayer[wallTile] & 7) + 1 != playerID) { + return; + } + this->buildingPlacementFail = FALSE; + this->field151_0x554998 = 1; + if ((this->MiscDisplayLayer[wallTile] & 0x400) != 0) { + this->buildingPlacementFail = TRUE; + } + checkMoat = false; + } + } + if (checkMoat) { + if (moatTile < 1 || (this->LogicLayer[moatTile] & L_MOAT) == 0 || buildingID != 0) { + if (this->field151_0x554998 != 0 || this->field152_0x55499c != 0) { + this->buildingPlacementFail = TRUE; + } + } else if (this->field151_0x554998 == 0) { + int moatID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(moatTile); + if (moatID == 0) { + return; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[this->moats[moatID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + return; + } + this->field152_0x55499c = 1; + this->buildingPlacementFail = (BOOLEnum)((this->MiscDisplayLayer[moatTile] & 0x400) != 0); + wallTile = moatTile; + } else { + this->buildingPlacementFail = TRUE; + } + } + + if (wallTile > 0 && this->UnitLayer[wallTile] != 0) { + this->buildingPlacementFail = TRUE; + } + if (buildingID != 0) { + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR) { + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SIEGE_THAT) { + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_SIGNPOST) { + this->buildingPlacementFail = TRUE; + } + } else { + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_UNKNOWN1: + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_SIGNPOST: + case OpenSHC::Map::Buildings::BT_CAMPGROUND: + case OpenSHC::Map::Buildings::BT_KEEPDOOR_LEFT: + case OpenSHC::Map::Buildings::BT_KEEPDOOR_RIGHT: + case OpenSHC::Map::Buildings::BT_KEEPDOOR: + case OpenSHC::Map::Buildings::BT_POND: + this->buildingPlacementFail = TRUE; + } + } + } + if ((int)buildingID < 0) { + this->field131_0x554954 = buildingID; + return; + } + } + + if ((this->LogicLayer[DAT_BuildingsState::instance.buildings[buildingID].currentTilePositionAdjusted] + & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) + == 0 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_GATEHOUSESMALL + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_WOODGATE1 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_WOODGATE2 + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KEEPDOOR + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_DRAWBRIDGE + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KILLINGPIT + && this->field151_0x554998 == 0 && this->field152_0x55499c == 0) { + this->buildingPlacementFail = TRUE; + } + this->field131_0x554954 = buildingID; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index baa6fee4a..375c4b452 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41959,7 +41959,7 @@ SHC_3BB0A8C1_0x00504A26 | 0.0% | Pending SHC_3BB0A8C1_0x00504A27 | 0.0% | Pending -SHC_3BB0A8C1_0x00504A30 | 0.0% | Pending +SHC_3BB0A8C1_0x00504A30 | 48.9% | 48.92% global instance base SHC_3BB0A8C1_0x00504E88 | 0.0% | Pending From ddf784b3b0c3e744da720a18a63f5b67af562f46 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:28:15 +0200 Subject: [PATCH 186/252] reimplement: SHC_3BB0A8C1_0x004F9A60 49.74% 49.70% global instance base --- .../isBuildingPlacementAllowedAtTile.cpp | 235 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/isBuildingPlacementAllowedAtTile.cpp diff --git a/src/OpenSHC/Map/TileMapState/isBuildingPlacementAllowedAtTile.cpp b/src/OpenSHC/Map/TileMapState/isBuildingPlacementAllowedAtTile.cpp new file mode 100644 index 000000000..ad9e6e751 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/isBuildingPlacementAllowedAtTile.cpp @@ -0,0 +1,235 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_DAIRY; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_HOP; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_WHEAT; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + @return int 0 if allowed, 1 if not allowed, 2 not allowed because of clashing building placement decompilerscript: + committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F9A60 + int TileMapState::isBuildingPlacementAllowedAtTile( + int tile, int playerID, MappersEnum commandBuildingType, int param_4) + { + uint logic = this->LogicLayer[tile]; + uint wallOrGate = logic & L_WALL_OR_GATEHOUSE; + uint height = this->HeightLayer[tile]; + if (wallOrGate != 0 && (this->WallOwnerLayer[tile] & 7) + 1 == playerID) { + /* a gate or tower on our own wall is measured against the ground, not the wall top */ + switch (commandBuildingType) { + case OpenSHC::Commands::M_MAPPER_GATEHOUSE: + case OpenSHC::Commands::M_MAPPER_GATE_MAIN: + case OpenSHC::Commands::M_MAPPER_GATE_INNER: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD: + case OpenSHC::Commands::M_MAPPER_GATE_POSTERN: + case OpenSHC::Commands::M_MAPPER_TOWER1: + case OpenSHC::Commands::M_MAPPER_TOWER2: + case OpenSHC::Commands::M_MAPPER_TOWER3: + case OpenSHC::Commands::M_MAPPER_TOWER4: + case OpenSHC::Commands::M_MAPPER_TOWER5: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1A: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1B: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1C: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1D: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1B: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2B: + height = this->DefaultHeightLayer[tile]; + } + } + + if (this->buildingHeightLimit < 0) { + if ((int)height < -this->buildingHeightLimit) { + return 1; + } + } else if (this->buildingHeightLimit < (int)height) { + if (commandBuildingType == OpenSHC::Commands::M_MAPPER_CATTLEFARM) { + this->placementWarning = 1; + return 1; + } + if (commandBuildingType == OpenSHC::Commands::M_MAPPER_APPLEFARM) { + this->placementWarning = 2; + return 1; + } + if (commandBuildingType == OpenSHC::Commands::M_MAPPER_HOPSFARM) { + this->placementWarning = 3; + return 1; + } + if (commandBuildingType != OpenSHC::Commands::M_MAPPER_WHEATFARM) { + return 1; + } + this->placementWarning = 4; + return 1; + } + if (this->buildingMaxHeightDifference + this->buildingMinHeight < (int)height) { + return 1; + } + if ((logic & L_PLAIN2_AND_PITCH) != 0 && commandBuildingType == OpenSHC::Commands::M_MAPPER_PITCH_DITCH) { + return 1; + } + if (this->BuildingLayer[tile] != 0) { + return 2; + } + + if (this->UnitLayer[tile] != 0) { + int unitID = (short)this->UnitLayer[tile]; + if (MACRO_CALL_MEMBER( + OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, DAT_GameSynchronyState::ptr)(playerID) + == FALSE) { + if (DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_CHICKEN) { + return 1; + } + } else { + if (DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_LORD) { + return 1; + } + if (DAT_UnitsState::instance.units[unitID].isSelectable_OR_matchTime != 0 + && DAT_UnitsState::instance.units[unitID].owner != playerID) { + return 1; + } + } + } + + if ((logic & L_SEA) != 0) { + return 1; + } + if ((logic & (L_BORDER | L_BORDER_EDGE)) != 0) { + return 1; + } + if ((logic & L_RIVER) != 0) { + return 1; + } + if (wallOrGate != 0) { + if ((this->WallOwnerLayer[tile] & 7) + 1 != playerID) { + return 1; + } + /* only a gate or a tower may be built onto a wall */ + switch (commandBuildingType) { + case OpenSHC::Commands::M_MAPPER_GATEHOUSE: + case OpenSHC::Commands::M_MAPPER_GATE_MAIN: + case OpenSHC::Commands::M_MAPPER_GATE_INNER: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD: + case OpenSHC::Commands::M_MAPPER_GATE_POSTERN: + case OpenSHC::Commands::M_MAPPER_TOWER1: + case OpenSHC::Commands::M_MAPPER_TOWER2: + case OpenSHC::Commands::M_MAPPER_TOWER3: + case OpenSHC::Commands::M_MAPPER_TOWER4: + case OpenSHC::Commands::M_MAPPER_TOWER5: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1A: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1B: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1C: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1D: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1B: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2B: + break; + default: + return 1; + } + } + if ((logic & L_PLAIN1_AND_FARM) != 0 && param_4 == 0) { + return 1; + } + if ((logic & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0) { + return 1; + } + + if ((logic & (L_TREE | L_TREE_VARIATION)) != 0 && this->OrganismLayer[tile] != 0 + && this->OrganismLayer[tile] < 2000) { + /* scrub can be built over, a real tree cannot, except by the AI outside solitary */ + switch (DAT_LandscapeState::instance.trees[this->OrganismLayer[tile]].treeType) { + case (TreeType)5: + case (TreeType)6: + case (TreeType)7: + case (TreeType)8: + case (TreeType)9: + case (TreeType)0xa: + case (TreeType)0xb: + case (TreeType)0xc: + case (TreeType)0xd: + case (TreeType)0xe: + case (TreeType)0x10: + case (TreeType)0x11: + case (TreeType)0x12: + case (TreeType)0x13: + break; + default: + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + return 1; + } + if (MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(playerID) + == 0) { + return 1; + } + } + } + + if ((logic & (L_FARM_FIELD_WHEAT | L_FARM_FIELD_HOP | L_FARM_FIELD_APPLE | L_FARM_FIELD_DAIRY)) != 0 + && param_4 == 0) { + return 1; + } + if ((logic & L_FORD) != 0) { + return 1; + } + + bool onRock = false; + if ((char)logic < 0 && wallOrGate == 0) { + onRock = true; + } + if ((!onRock || this->buildingPlacementProperty_4 != 0) + && ((logic & L_MOAT) == 0 || this->buildingPlacementProperty_7 != 0) + && (this->buildingPlacementProperty_6 == 2 || (logic & L_MARSH) == 0 + || this->buildingPlacementProperty_6 != 0)) { + return 0; + } + return 1; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 375c4b452..4b401956c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -39413,7 +39413,7 @@ SHC_3BB0A8C1_0x004F9980 | 34.2% | ecx not kept across callee SHC_3BB0A8C1_0x004F99D0 | 0.0% | Pending -SHC_3BB0A8C1_0x004F9A60 | 0.0% | Pending +SHC_3BB0A8C1_0x004F9A60 | 49.7% | 49.70% global instance base SHC_3BB0A8C1_0x004F9D64 | 0.0% | Pending From c36b4caecdf829949a45121d9a983e3cc1e19215 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:35:03 +0200 Subject: [PATCH 187/252] header: name the orientation table at 0x7c8 in TerrainDefinedData setConstructionGFXLayerBasedOnPlacementChecks indexes 32 ints there with (tile + group * 4) and compares each against mapOrientation. The header only had padding_0x694, so Ghidra emitted an undeclared field_0x7c8 and the file could not compile. The padding is split; the span is unchanged. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TerrainDefinedData.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TerrainDefinedData.hpp b/src/OpenSHC/Map/TerrainDefinedData.hpp index 4469b9a93..a2a38ceee 100644 --- a/src/OpenSHC/Map/TerrainDefinedData.hpp +++ b/src/OpenSHC/Map/TerrainDefinedData.hpp @@ -58,7 +58,9 @@ namespace Map { XYPair field370_0x5cc; // 0x000005CC length: 8 undefined1 padding_0x5d4[184]; // 0x000005D4 length: 184 XYPair field555_0x68c; // 0x0000068C length: 8 - undefined1 padding_0x694[440]; // 0x00000694 length: 440 + undefined1 padding_0x694[308]; // 0x00000694 length: 308 + int field600_0x7c8[32]; // 0x000007C8 length: 128 + undefined1 padding_0x848[4]; // 0x00000848 length: 4 int field996_0x84c[25]; // 0x0000084C length: 100 undefined1 padding_0x8b0[4]; // 0x000008B0 length: 4 int field1001_0x8b4[25]; // 0x000008B4 length: 100 From c01b32183c9a3889add8bc0069051c995d051578 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:35:04 +0200 Subject: [PATCH 188/252] reimplement: SHC_3BB0A8C1_0x00504F10 28.87% 28.87% repaired from unbuildab --- ...tructionGFXLayerBasedOnPlacementChecks.cpp | 794 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 795 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/setConstructionGFXLayerBasedOnPlacementChecks.cpp diff --git a/src/OpenSHC/Map/TileMapState/setConstructionGFXLayerBasedOnPlacementChecks.cpp b/src/OpenSHC/Map/TileMapState/setConstructionGFXLayerBasedOnPlacementChecks.cpp new file mode 100644 index 000000000..66a126af3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/setConstructionGFXLayerBasedOnPlacementChecks.cpp @@ -0,0 +1,794 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Type propagation algorithm not settling + */ + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00504F10 + int TileMapState::setConstructionGFXLayerBasedOnPlacementChecks(int x, int y, MappersEnum type, int size) + { + int iVar1; + BuildingType BVar2; + undefined2 uVar8; + int iVar3; + int iVar4; + int iVar5; + int iVar6; + int iVar7; + ushort uVar9; + MappersEnum MVar10; + XYPair* pXVar11; + int* piVar12; + int iVar13; + int iVar14; + int iVar15; + int local_14; + int _offset; + short sprite; + short command; + iVar1 = x; + command = (short)type; + iVar14 = this->field188_0x554a14; + local_14 = 0; + this->field188_0x554a14 = 0; + if (iVar14 == 0) { + if (this->buildingPlacementFail == 2) { + this->field188_0x554a14 = 0; + return (int)(2); + } + if (this->buildingPlacementFail != FALSE) { + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + local_14, size); + iVar14 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if ((this->LogicLayer[iVar14] & 0x10000500U) == 0) { + iVar15 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar14, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + this->ConstructionGFXLayer[iVar14] = (-(ushort)(iVar15 != 0) & 0xfff9) + 0x3e; + } + local_14 = local_14 + 1; + } while (local_14 < this->constructionTileCount); + uVar8 = (undefined2)((uint)local_14 >> 0x10); + if (((command == OpenSHC::Commands::M_MAPPER_KEEP1) || (command == OpenSHC::Commands::M_MAPPER_KEEP2)) + || (command == OpenSHC::Commands::M_MAPPER_KEEP3)) { + piVar12 + = (int*)((int)DAT_TerrainDefinedData::ptr + ((short)command + -0x3c) * 0x60 + 0x264); + x = 3; + do { + iVar14 = DAT_ViewportRenderState::instance.translationMatrix[piVar12[1] + y].addXgetTile + + *piVar12 + iVar1; + if ((this->LogicLayer[iVar14] & 0x10000500U) == 0) { + iVar15 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar14, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + this->ConstructionGFXLayer[iVar14] = (-(ushort)(iVar15 != 0) & 0xfff9) + 0x3e; + } + piVar12 = piVar12 + 2; + x = x + -1; + } while (x != 0); + iVar3 = ((short)command + -0x3c) * 0x20; + iVar14 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar3 + 900); + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar3 + 0x388); + local_14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + local_14, 7); + iVar13 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + iVar15] + .addXgetTile + + this->buildingX + iVar1 + iVar14; + if ((this->LogicLayer[iVar13] & 0x10000500U) == 0) { + iVar4 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar13, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + this->ConstructionGFXLayer[iVar13] = (-(ushort)(iVar4 != 0) & 0xfff9) + 0x3e; + } + local_14 = local_14 + 1; + } while (local_14 < this->constructionTileCount); + iVar14 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar3 + 0x3e4); + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar3 + 1000); + iVar3 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar3, 5); + iVar13 = this->buildingY + iVar15 + y; + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[iVar13].addXgetTile + + this->buildingX + iVar14 + iVar1; + if ((this->LogicLayer[iVar4] & 0x10000500U) == 0) { + iVar13 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar4, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + iVar13 = (-(uint)(iVar13 != 0) & 0xfffffff9) + 0x3e; + this->ConstructionGFXLayer[iVar4] = (ushort)iVar13; + } + uVar8 = (undefined2)((uint)iVar13 >> 0x10); + iVar3 = iVar3 + 1; + } while (iVar3 < this->constructionTileCount); + } + if (((command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1A) || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1B)) + || ((command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1C || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1D)))) { + MVar10 = (MappersEnum)command; + iVar14 = MVar10 * 3 + -0x1a4; + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar14 * 8 + 0x56c); + iVar14 = iVar14 * 8; + iVar3 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar14 + 0x570); + iVar13 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar13, 3); + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + iVar3 + y] + .addXgetTile + + this->buildingX + iVar15 + iVar1; + iVar4 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar5, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), MVar10, 0); + iVar13 = iVar13 + 1; + this->ConstructionGFXLayer[iVar5] = (-(ushort)(iVar4 != 0) & 0xfff9) + 0x3e; + } while (iVar13 < this->constructionTileCount); + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar14 + 0x578); + iVar14 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar14 + 0x57c); + iVar3 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar3, 3); + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + iVar14 + y] + .addXgetTile + + this->buildingX + iVar15 + iVar1; + iVar13 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar4, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), MVar10, 0); + iVar3 = iVar3 + 1; + this->ConstructionGFXLayer[iVar4] = (-(ushort)(iVar13 != 0) & 0xfff9) + 0x3e; + } while (iVar3 < this->constructionTileCount); + piVar12 = (int*)((int)DAT_TerrainDefinedData::ptr + (MVar10 * 3 + -0x1a4) * 0x10 + 0x5cc); + type = OpenSHC::Commands::M_MAPPER_FOREST; + do { + iVar15 = DAT_ViewportRenderState::instance.translationMatrix[piVar12[1] + y].addXgetTile + + *piVar12 + iVar1; + iVar14 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar15, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), MVar10, 0); + iVar14 = (-(uint)(iVar14 != 0) & 0xfffffff9) + 0x3e; + piVar12 = piVar12 + 2; + type = (MappersEnum)(type - OpenSHC::Commands::M_MAPPER_AREA); + this->ConstructionGFXLayer[iVar15] = (ushort)iVar14; + } while (type != OpenSHC::Commands::M_MAPPER_NULL); + return iVar14; + } + if ((command == OpenSHC::Commands::M_MAPPER_BARRACKS_EURO) || (command == OpenSHC::Commands::M_MAPPER_BARRACKS_ARAB)) { + iVar14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar14, 5); + iVar3 = this->buildingX; + iVar15 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile; + if ((this->LogicLayer[iVar1 + this->buildingX + iVar15 + 5] & 0x10000500U) == 0) { + iVar13 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar15 + this->buildingX + iVar1 + 5, + (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + this->ConstructionGFXLayer[iVar1 + iVar3 + iVar15 + 5] + = (-(ushort)(iVar13 != 0) & 0xfff9) + 0x3e; + } + iVar14 = iVar14 + 1; + } while (iVar14 < this->constructionTileCount); + iVar14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar14, 5); + iVar15 + = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5].addXgetTile + + this->buildingX + iVar1; + if ((this->LogicLayer[iVar15] & 0x10000500U) == 0) { + iVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar15, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + this->ConstructionGFXLayer[iVar15] = (-(ushort)(iVar3 != 0) & 0xfff9) + 0x3e; + } + iVar14 = iVar14 + 1; + } while (iVar14 < this->constructionTileCount); + iVar14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar14, 5); + iVar3 = this->buildingX; + iVar13 = this->buildingY + y + 5; + iVar15 + = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5].addXgetTile; + if ((this->LogicLayer[iVar1 + this->buildingX + iVar15 + 5] & 0x10000500U) == 0) { + iVar13 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar15 + this->buildingX + iVar1 + 5, + (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + iVar13 = (-(uint)(iVar13 != 0) & 0xfffffff9) + 0x3e; + this->ConstructionGFXLayer[iVar1 + iVar3 + iVar15 + 5] = (ushort)iVar13; + } + iVar14 = iVar14 + 1; + } while (iVar14 < this->constructionTileCount); + return iVar13; + } + if ((command != OpenSHC::Commands::M_MAPPER_ENGINEERS_GUILD) && (command != OpenSHC::Commands::M_MAPPER_TUNNELERS_GUILD)) { + if (command != OpenSHC::Commands::M_MAPPER_OIL_SMELTER) { + /* the original returns eax with a leftover tile index still in its high half */ + return (ushort)command; + } + iVar14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar14, 4); + iVar15 = this->buildingY + y + 4; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 4].addXgetTile + + this->buildingX + iVar1; + if ((this->LogicLayer[iVar3] & 0x10000500U) == 0) { + iVar15 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar3, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + OpenSHC::Commands::M_MAPPER_OIL_SMELTER, 0); + iVar15 = (-(uint)(iVar15 != 0) & 0xfffffff9) + 0x3e; + this->ConstructionGFXLayer[iVar3] = (ushort)iVar15; + } + iVar14 = iVar14 + 1; + } while (iVar14 < this->constructionTileCount); + return iVar15; + } + iVar14 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar14, 5); + iVar15 = (this->buildingY + y + 5) * 3; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5].addXgetTile + + this->buildingX + iVar1; + if ((this->LogicLayer[iVar3] & 0x10000500U) == 0) { + iVar15 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar3, (int)((int)(DAT_GameSynchronyState::instance.currentPlayerSlotID)), + (MappersEnum)command, 0); + iVar15 = (-(uint)(iVar15 != 0) & 0xfffffff9) + 0x3e; + this->ConstructionGFXLayer[iVar3] = (ushort)iVar15; + } + iVar14 = iVar14 + 1; + } while (iVar14 < this->constructionTileCount); + return iVar15; + } + } else { + BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)((MappersEnum)command); + this->buildingSpriteSheetID_1 = DAT_BuildingDefinedData::instance.Building_SpriteSheet_ID_Array_1[BVar2].intValue; + this->buildingSpriteID1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getSpriteID, + DAT_BuildingsState::ptr)((MappersEnum)command); + this->buildingSpriteID2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getSpriteID2, + DAT_BuildingsState::ptr)((MappersEnum)command); + } + if (command == OpenSHC::Commands::M_MAPPER_WHEATFARM) { + size = 3; + } else if (command == OpenSHC::Commands::M_MAPPER_HOPSFARM) { + size = 3; + } else if (command == OpenSHC::Commands::M_MAPPER_APPLEFARM) { + size = 3; + } else if (command == OpenSHC::Commands::M_MAPPER_CATTLEFARM) { + size = 3; + } else if ((((command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1A) || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1C)) + || (command == OpenSHC::Commands::M_MAPPER_GATE_STONE1A)) + || (command == OpenSHC::Commands::M_MAPPER_GATE_STONE2A)) { + this->field78_0x55488c = 0x51; + } else if (((command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1B) || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1D)) + || ((command == OpenSHC::Commands::M_MAPPER_GATE_STONE1B || (command == OpenSHC::Commands::M_MAPPER_GATE_STONE2B)))) { + this->field78_0x55488c = 0x50; + } + MVar10 = (MappersEnum)command; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(local_14, size); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + iVar1; + iVar15 = this->uiBuildingRotation; + if (((this->uiBuildingRotation != 0xf) && (this->uiBuildingRotation != 8)) + && (iVar15 = this->uiBuildingRotation - this->mapOrientation, iVar15 < 0)) { + iVar15 = iVar15 + 8; + } + sprite = (short)this->buildingSpriteID1; + if ((this->mapOrientation == 2) || (this->mapOrientation == 6)) { + if (this->field78_0x55488c != 0x51) + goto LAB_00505714; + } else if (this->field78_0x55488c == 0x51) { + LAB_00505714: + sprite = (short)this->buildingSpriteID2; + } + if ((command == OpenSHC::Commands::M_MAPPER_DRAWBRIDGE) && (iVar15 != 0)) { + if (iVar15 == 2) { + iVar15 = 3; + } else if (iVar15 == 4) { + iVar15 = 2; + } else if (iVar15 == 6) { + iVar15 = 1; + } + } + BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(MVar10); + if (BVar2 == OpenSHC::Map::Buildings::BT_UNKNOWN1) { + sprite = sprite + (short)(&DAT_BuildingDefinedData::instance.field209_0x976c[9].y)[MVar10]; + } else { + BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(MVar10); + if (BVar2 == OpenSHC::Map::Buildings::BT_HOVEL) { + sprite = (short)DAT_BuildingDefinedData::instance.SomeSpriteArray1[DAT_GameState::instance + .playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .hovelCountUpToEight]; + } + } + if (this->uiBuildingRotation == 0xf) { + this->ConstructionGFXLayer[iVar3] + = ((short)GMTotalPicturesProcessed::instance[this->buildingSpriteSheetID_1] + sprite + + (short)this->buildingRotationRelatedValue) + - 1; + } else { + this->ConstructionGFXLayer[iVar3] + = ((short)(iVar15 * size * size) + + (short)GMTotalPicturesProcessed::instance[this->buildingSpriteSheetID_1] + sprite + + (short)this->buildingRotationRelatedValue) + - 1; + } + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + local_14 = local_14 + 1; + if (this->constructionTileCount <= local_14) { + iVar15 = (ushort)command; + if ((((command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1A) || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1B)) + || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1C)) + || (command == OpenSHC::Commands::M_MAPPER_GATE_WOOD1D)) { + /* + 0 3 6 9 + */ + _offset = MVar10 * 3 + -420; + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + _offset * 8 + 0x50c); + iVar3 = *(int*)((int)DAT_TerrainDefinedData::ptr + _offset * 8 + 0x510); + /* + 0 24 48 72 + */ + iVar4 = _offset * 8; + iVar13 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 0x514); + iVar5 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar5, 2); + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[iVar3 + y + this->buildingY] + .addXgetTile + + this->buildingX + iVar15 + iVar1; + this->ConstructionGFXLayer[iVar6] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[0x34]; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar6] = this->MiscDisplayLayer[iVar6] | 0x8000; + } + iVar5 = iVar5 + 1; + } while (iVar5 < this->constructionTileCount); + pXVar11 = &DAT_TerrainDefinedData::instance.field555_0x68c + iVar13 * 5; + iVar5 = 0; + do { + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[pXVar11->y + iVar3 + y].addXgetTile + + pXVar11->x + iVar15 + iVar1; + if (iVar5 < 1) { + this->ConstructionGFXLayer[iVar6] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x60e + (short)iVar5; + } else { + iVar7 = DAT_TerrainDefinedData::instance.field600_0x7c8[iVar5 + iVar13 * 4] + - this->mapOrientation; + if (iVar7 < 0) { + iVar7 = iVar7 + 8; + } + this->ConstructionGFXLayer[iVar6] = (short)GMTotalPicturesProcessed::instance[0x34] + + (short)(iVar7 / 2) * 4 + 0x60e + (short)iVar5; + } + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar6] = this->MiscDisplayLayer[iVar6] | 0x8000; + } + iVar5 = iVar5 + 1; + pXVar11 = pXVar11 + 1; + } while (iVar5 < 5); + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 0x518); + iVar3 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 0x51c); + iVar13 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 0x520); + iVar4 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar4, 2); + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[iVar3 + y + this->buildingY] + .addXgetTile + + this->buildingX + iVar15 + iVar1; + this->ConstructionGFXLayer[iVar5] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[0x34]; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar5] = this->MiscDisplayLayer[iVar5] | 0x8000; + } + iVar4 = iVar4 + 1; + } while (iVar4 < this->constructionTileCount); + pXVar11 = &DAT_TerrainDefinedData::instance.field555_0x68c + iVar13 * 5; + iVar4 = 0; + do { + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[pXVar11->y + iVar3 + y].addXgetTile + + pXVar11->x + iVar15 + iVar1; + if (iVar4 < 1) { + this->ConstructionGFXLayer[iVar5] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x60e + (short)iVar4; + } else { + iVar6 = DAT_TerrainDefinedData::instance.field600_0x7c8[iVar4 + iVar13 * 4] + - this->mapOrientation; + if (iVar6 < 0) { + iVar6 = iVar6 + 8; + } + this->ConstructionGFXLayer[iVar5] = (short)GMTotalPicturesProcessed::instance[0x34] + + (short)(iVar6 / 2) * 4 + 0x60e + (short)iVar4; + } + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar5] = this->MiscDisplayLayer[iVar5] | 0x8000; + } + iVar4 = iVar4 + 1; + pXVar11 = pXVar11 + 1; + } while (iVar4 < 5); + piVar12 = (int*)((int)DAT_TerrainDefinedData::ptr + (MVar10 * 3 + -0x1a4) * 0x10 + 0x5cc); + type = OpenSHC::Commands::M_MAPPER_FOREST; + do { + iVar15 = DAT_ViewportRenderState::instance.translationMatrix[piVar12[1] + y].addXgetTile + iVar1 + + *piVar12; + this->ConstructionGFXLayer[iVar15] = ((byte)this->RandomLayer[iVar15] & 3) + 0x138 + + (short)GMTotalPicturesProcessed::instance[6]; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + piVar12 = piVar12 + 2; + type = (MappersEnum)(type - OpenSHC::Commands::M_MAPPER_AREA); + } while (type != OpenSHC::Commands::M_MAPPER_NULL); + } else { + if (command == OpenSHC::Commands::M_MAPPER_WHEATFARM) { + iVar15 = 0; + do { + iVar3 = DAT_GameState::instance + .playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .unkWheatFarmOrientation; + iVar3 = DAT_ViewportRenderState::instance + .translationMatrix + [DAT_TerrainDefinedData::instance.WheatFarmTiles[iVar3][iVar15].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.WheatFarmTiles[iVar3][iVar15].x + iVar1; + this->ConstructionGFXLayer[iVar3] + = ((byte)this->RandomLayer[iVar3] & 3) + (short)GMTotalPicturesProcessed::instance[0xe]; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < 0x24); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_HOPSFARM) { + iVar15 = 0; + do { + iVar3 = *(int*)&DAT_GameState::instance + .playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .unkHopFarmVariation; + iVar3 = DAT_ViewportRenderState::instance + .translationMatrix + [DAT_TerrainDefinedData::instance.HopFarmProperty1[iVar3][iVar15].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.HopFarmProperty1[iVar3][iVar15].x + iVar1; + this->ConstructionGFXLayer[iVar3] = ((byte)this->RandomLayer[iVar3] & 1) * 9 + 0x25 + + (short)GMTotalPicturesProcessed::instance[0xe]; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < 0x18); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_CATTLEFARM) { + iVar15 = 0; + do { + iVar3 = DAT_GameState::instance + .playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .dairyFarmVariationMod4; + iVar13 + = DAT_ViewportRenderState::instance + .translationMatrix + [DAT_TerrainDefinedData::instance.field1009_0xf5c[iVar3][iVar15 + 4].offset.y + + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field1009_0xf5c[iVar3][iVar15 + 4].offset.x + iVar1; + iVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getRubbleGraphicStageForDamageLevel, this)( + DAT_TerrainDefinedData::instance.field1009_0xf5c[iVar3][iVar15 + 4].property); + iVar3 = iVar3 + 0x37 + GMTotalPicturesProcessed::instance[0xe]; + this->ConstructionGFXLayer[iVar13] = (ushort)iVar3; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar13] = this->MiscDisplayLayer[iVar13] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < 0x17); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_APPLEFARM) { + pXVar11 = DAT_TerrainDefinedData::instance.AppleFarmOffsets; + do { + iVar15 = DAT_ViewportRenderState::instance.translationMatrix[pXVar11->y + y].addXgetTile + + pXVar11->x + iVar1; + this->ConstructionGFXLayer[iVar15] = (short)GMTotalPicturesProcessed::instance[0xe] + 0x3d; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + pXVar11 = pXVar11 + 1; + } while ((int)pXVar11 < 0xb49eb0); + return iVar15; + } + if ((command == OpenSHC::Commands::M_MAPPER_BARRACKS_EURO) || (command == OpenSHC::Commands::M_MAPPER_BARRACKS_ARAB)) { + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 5); + iVar13 = this->buildingX; + iVar3 + = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile; + this->ConstructionGFXLayer[iVar1 + this->buildingX + iVar3 + 5] + = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x48; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar1 + iVar13 + iVar3 + 5] + = this->MiscDisplayLayer[iVar1 + iVar13 + iVar3 + 5] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 5); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5] + .addXgetTile + + this->buildingX + iVar1; + this->ConstructionGFXLayer[iVar3] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x7a; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 5); + iVar13 = this->buildingX; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5] + .addXgetTile; + iVar4 = iVar3 + this->buildingX; + this->ConstructionGFXLayer[iVar1 + this->buildingX + iVar3 + 5] + = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x61; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar1 + iVar13 + iVar3 + 5] + = this->MiscDisplayLayer[iVar1 + iVar13 + iVar3 + 5] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + return iVar4 + iVar1 + 5; + } + if (command == OpenSHC::Commands::M_MAPPER_ENGINEERS_GUILD) { + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 5); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5] + .addXgetTile + + this->buildingX + iVar1; + this->ConstructionGFXLayer[iVar3] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x93; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_TUNNELERS_GUILD) { + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 5); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 5] + .addXgetTile + + this->buildingX + iVar1; + this->ConstructionGFXLayer[iVar3] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0xac; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_OIL_SMELTER) { + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 4); + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[y + this->buildingY + 4] + .addXgetTile + + this->buildingX + iVar1; + this->ConstructionGFXLayer[iVar3] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x128; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + return iVar3; + } + if (command == OpenSHC::Commands::M_MAPPER_KEEP1) { + uVar9 = (ushort)(this->mapOrientation == 2); + iVar15 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[0][0].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[0][0].x + iVar1; + this->ConstructionGFXLayer[iVar15] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x523 + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + iVar15 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[0][1].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[0][1].x + iVar1; + this->ConstructionGFXLayer[iVar15] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x52e + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + iVar15 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field130_0x264[0][2].y + y] + .addXgetTile + + DAT_TerrainDefinedData::instance.field130_0x264[0][2].x + iVar1; + this->ConstructionGFXLayer[iVar15] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x527 + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + iVar3 = iVar1 + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[0][0].xOffset; + iVar13 = y + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[0][0].yOffset; + iVar15 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar15, 7); + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + iVar13] + .addXgetTile + + this->buildingX + iVar3; + this->ConstructionGFXLayer[iVar4] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x17; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar4] = this->MiscDisplayLayer[iVar4] | 0x8000; + } + iVar15 = iVar15 + 1; + } while (iVar15 < this->constructionTileCount); + iVar1 = DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[0][0].xOffset + iVar1; + iVar15 = DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[0][0].yOffset + y; + iVar3 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar3, 5); + iVar13 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + iVar15] + .addXgetTile + + this->buildingX + iVar1; + this->ConstructionGFXLayer[iVar13] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[7] + 0x19; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar13] = this->MiscDisplayLayer[iVar13] | 0x8000; + } + iVar3 = iVar3 + 1; + } while (iVar3 < this->constructionTileCount); + return iVar13; + } + if ((command == OpenSHC::Commands::M_MAPPER_KEEP2) || (command == OpenSHC::Commands::M_MAPPER_KEEP3)) { + uVar9 = (ushort)(this->mapOrientation == 2); + iVar15 = (MVar10 - OpenSHC::Commands::M_MAPPER_KEEP1) * 0x60; + iVar3 = DAT_ViewportRenderState::instance + .translationMatrix[*(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x268) + y] + .addXgetTile + + *(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x264) + iVar1; + this->ConstructionGFXLayer[iVar3] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x521 + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar3 = DAT_ViewportRenderState::instance + .translationMatrix[*(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x270) + y] + .addXgetTile + + *(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x26c) + iVar1; + this->ConstructionGFXLayer[iVar3] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x529 + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar3] = this->MiscDisplayLayer[iVar3] | 0x8000; + } + iVar15 = DAT_ViewportRenderState::instance + .translationMatrix[*(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x278) + y] + .addXgetTile + + *(int*)((int)DAT_TerrainDefinedData::ptr + iVar15 + 0x274) + iVar1; + this->ConstructionGFXLayer[iVar15] + = (short)GMTotalPicturesProcessed::instance[0x34] + 0x525 + uVar9; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar15] = this->MiscDisplayLayer[iVar15] | 0x8000; + } + iVar13 = (MVar10 - OpenSHC::Commands::M_MAPPER_KEEP1) * 0x20; + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar13 + 900); + iVar3 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar13 + 0x388); + iVar4 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar4, 7); + iVar5 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y + iVar3] + .addXgetTile + + this->buildingX + iVar1 + iVar15; + this->ConstructionGFXLayer[iVar5] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[6] + 0x17; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar5] = this->MiscDisplayLayer[iVar5] | 0x8000; + } + iVar4 = iVar4 + 1; + } while (iVar4 < this->constructionTileCount); + iVar15 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar13 + 0x3e4); + iVar3 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar13 + 1000); + iVar13 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar13, 5); + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + iVar3 + y] + .addXgetTile + + this->buildingX + iVar15 + iVar1; + this->ConstructionGFXLayer[iVar4] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[7] + 0x19; + if (iVar14 != 0) { + this->MiscDisplayLayer[iVar4] = this->MiscDisplayLayer[iVar4] | 0x8000; + } + iVar13 = iVar13 + 1; + } while (iVar13 < this->constructionTileCount); + return iVar4; + } + } + return iVar15; + } + } while (true); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4b401956c..2ecf9b310 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42069,7 +42069,7 @@ SHC_3BB0A8C1_0x00504ED1 | 0.0% | Pending SHC_3BB0A8C1_0x00504EE0 | 38.5% | needs callee LTCG (ecx reuse) -SHC_3BB0A8C1_0x00504F10 | 0.0% | Pending +SHC_3BB0A8C1_0x00504F10 | 28.9% | 28.87% repaired from unbuildab SHC_3BB0A8C1_0x005050F0 | 0.0% | Pending From 11c0047a06af5d890edf992676f88fb9860f9039 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 21:38:27 +0200 Subject: [PATCH 189/252] reimplement: SHC_3BB0A8C1_0x005146D0 40.44% 47.46% regalloc --- src/OpenSHC/Map/TileMapState/placeKeep.cpp | 232 +++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeKeep.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeKeep.cpp b/src/OpenSHC/Map/TileMapState/placeKeep.cpp new file mode 100644 index 000000000..c2da3db09 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeKeep.cpp @@ -0,0 +1,232 @@ + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/Player/PlayerDataBuildingCategoryEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic1.hpp" +#include "OpenSHC/Map/LogicHelpers/Logic2.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + + using OpenSHC::Game::Player::PlayerDataBuildingCategoryEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::LogicHelpers::Logic1; + using OpenSHC::Map::LogicHelpers::Logic2; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005146D0 + void TileMapState::placeKeep( + int playerID, uint x, uint y, BuildingType type, uint size, int orientation, int xyValue) + { + uint baseX = x; + uint baseY = y; + if (this->field195_0x554a24 != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::demolishBuildingsInKeepsConstructionFootprint, this)( + playerID, x, y, type, size, orientation, xyValue); + this->field195_0x554a24 = 0; + } + + int uid = DAT_GameCore::instance.uniqueGameObjectTracker; + int keepKind = 0; + byte logic2 = this->Logic2Layer[DAT_ViewportRenderState::instance.translationMatrix[baseY].addXgetTile + baseX]; + int keepID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, baseX, baseY, xyValue, (BuildingType)(short)type, size, playerID, 0xf); + this->placedBuildingID = keepID; + DAT_BuildingsState::instance.buildings[keepID].uidWhenPlaced = uid; + short keepOrientation = (short)orientation; + DAT_BuildingsState::instance.buildings[keepID].orientation = keepOrientation; + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::computeBuildingCategoryEntryPointAndDestroyEarlierBuilding, DAT_GameState::ptr)( + keepID, playerID, OpenSHC::Game::Player::PDBCE_KEEP); + if (orientation == 0xf) { + orientation = 0; + } + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, size); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + baseY].addXgetTile + this->buildingX + baseX; + if (index < 0x24) { + DAT_BuildingsState::instance.buildings[keepID].tileRefs[index] = tile; + } + this->HeightLayer[tile] = (byte)xyValue; + if ((short)type == OpenSHC::Map::Buildings::BT_MANORHOUSE) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_KEEP_NON_MANOR_HOUSE; + } + this->BuildingLayer[tile] = (short)keepID; + this->BuildingWasLayer[tile] = (uchar)type; + /* grass and scrub come back as scrub, anything else as bare earth */ + Logic2 terrain; + uint brush; + if ((logic2 & (OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS | OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB)) == 0) { + terrain = OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + brush = 6; + } else { + terrain = OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + brush = 3; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)( + playerID, tile, this->buildingY + baseY, brush, OpenSHC::Map::LogicHelpers::L_NONE, terrain); + this->ChangedLayer[tile] = 2; + index++; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(keepID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(keepID); + if ((short)type == OpenSHC::Map::Buildings::BT_MANORHOUSE || (short)type == OpenSHC::Map::Buildings::BT_STONEKEEP) { + keepKind = 2; + } + + /* the three keep doors and the two outbuildings are laid out per keep type and orientation */ + int group = orientation / 2 + -0xa0 + (short)type * 4; + { + int doorX = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 0].x + baseX; + uint doorY = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 0].y + baseY; + int doorTile = DAT_ViewportRenderState::instance.translationMatrix[doorY].addXgetTile + doorX; + int doorID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, doorX, doorY, xyValue, OpenSHC::Map::Buildings::BT_KEEPDOOR_LEFT, 1, playerID, 0xf); + DAT_BuildingsState::instance.buildings[doorID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[doorID].unknownManorHouseOrStoneKeepRelated = keepKind; + DAT_BuildingsState::instance.buildings[doorID].quarryStockpileID = (short)this->placedBuildingID; + DAT_BuildingsState::instance.buildings[doorID].orientation = keepOrientation; + this->LogicLayer[doorTile] = this->LogicLayer[doorTile] | L_BUILDING; + this->BuildingLayer[doorTile] = (short)doorID; + this->ChangedLayer[doorTile] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)( + (short)DAT_BuildingsState::instance.buildings[doorID].y, doorTile); + } + + { + int doorX = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 1].x + baseX; + uint doorY = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 1].y + baseY; + int doorTile = DAT_ViewportRenderState::instance.translationMatrix[doorY].addXgetTile + doorX; + int doorID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, doorX, doorY, xyValue, OpenSHC::Map::Buildings::BT_KEEPDOOR, 1, playerID, 0xf); + DAT_BuildingsState::instance.buildings[doorID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[doorID].unknownManorHouseOrStoneKeepRelated = keepKind / 2; + DAT_BuildingsState::instance.buildings[doorID].quarryStockpileID = (short)this->placedBuildingID; + DAT_BuildingsState::instance.buildings[doorID].orientation = keepOrientation; + this->MiscDisplayLayer[doorTile] = this->MiscDisplayLayer[doorTile] | 4; + this->BuildingLayer[doorTile] = (short)doorID; + this->ChangedLayer[doorTile] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)( + (short)DAT_BuildingsState::instance.buildings[doorID].y, doorTile); + } + + { + int doorX = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 2].x + baseX; + uint doorY = DAT_TerrainDefinedData::instance.field130_0x264[0][group * 3 + 2].y + baseY; + int doorTile = DAT_ViewportRenderState::instance.translationMatrix[doorY].addXgetTile + doorX; + int doorID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, doorX, doorY, xyValue, OpenSHC::Map::Buildings::BT_KEEPDOOR_RIGHT, 1, playerID, 0xf); + DAT_BuildingsState::instance.buildings[doorID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[doorID].unknownManorHouseOrStoneKeepRelated = keepKind; + DAT_BuildingsState::instance.buildings[doorID].quarryStockpileID = (short)this->placedBuildingID; + DAT_BuildingsState::instance.buildings[doorID].orientation = keepOrientation; + this->LogicLayer[doorTile] = this->LogicLayer[doorTile] | L_BUILDING; + this->BuildingLayer[doorTile] = (short)doorID; + this->ChangedLayer[doorTile] = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)( + (short)DAT_BuildingsState::instance.buildings[doorID].y, doorTile); + } + + uint campX = baseX + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[0][group].xOffset; + uint campY = baseY + DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x384[0][group].yOffset; + int campID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::setupBuildingData, DAT_BuildingsState::ptr)( + playerID, campX, campY, xyValue, OpenSHC::Map::Buildings::BT_CAMPGROUND, 7, playerID, 0xf); + DAT_BuildingsState::instance.buildings[campID].uidWhenPlaced = uid; + DAT_BuildingsState::instance.buildings[campID].quarryStockpileID = (short)this->placedBuildingID; + DAT_BuildingsState::instance.buildings[campID].orientation = keepOrientation; + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::computeBuildingCategoryEntryPointAndDestroyEarlierBuilding, DAT_GameState::ptr)( + campID, playerID, OpenSHC::Game::Player::PDBCE_CAMPGROUND); + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 7); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)( + DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + campY].addXgetTile + this->buildingX + campX); + index++; + } while (index < this->constructionTileCount); + + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + index, DAT_BuildingsState::instance.buildings[campID].widthOrHeight); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + campY].addXgetTile + this->buildingX + campX; + if (index < 0x18) { + DAT_BuildingsState::instance.buildings[campID].tileRefs[index] + = DAT_ViewportRenderState::instance + .translationMatrix[(short)DAT_BuildingsState::instance.buildings[campID].y + DAT_TerrainDefinedData::instance.field197_0x444[index].y] + .addXgetTile + + (short)DAT_BuildingsState::instance.buildings[campID].x + DAT_TerrainDefinedData::instance.field197_0x444[index].x; + } + this->HeightLayer[tile] = (byte)xyValue; + /* only the campground's cross of five middle tiles blocks movement */ + if (this->buildingX == 3 && this->buildingY == 3) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } + if (this->buildingX == 3 && this->buildingY == 2) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } + if (this->buildingX == 3 && this->buildingY == 4) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } + if (this->buildingX == 2 && this->buildingY == 3) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } + if (this->buildingX == 4 && this->buildingY == 3) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_BUILDING; + } + this->BuildingLayer[tile] = (short)campID; + this->ChangedLayer[tile] = 2; + Logic2 terrain; + uint brush; + if ((logic2 & (OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS | OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB)) == 0) { + terrain = OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + brush = 6; + } else { + terrain = OpenSHC::Map::LogicHelpers::L2_THICK_SCRUB; + brush = 3; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setTerrain, this)( + playerID, tile, this->buildingY + campY, brush, OpenSHC::Map::LogicHelpers::L_NONE, terrain); + index++; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::setMiscDisplayLayer, this)(campID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::updatePathLinkagesForBuilding, this)(campID); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(10, campX, campY); + + int stockpileX = DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[0][group].xOffset; + int stockpileY = DAT_TerrainDefinedData::instance.keepOutbuildingOffsets_0x3e4[0][group].yOffset; + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, 5); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::resetTileAndClearMoat, this)( + DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + stockpileY + baseY].addXgetTile + this->buildingX + + stockpileX + baseX); + index++; + } while (index < this->constructionTileCount); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeStockpile, this)( + playerID, stockpileX + baseX, stockpileY + baseY, 10, 5, 0xf, xyValue); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2ecf9b310..cdaa6509e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44747,7 +44747,7 @@ SHC_3BB0A8C1_0x00514480 | 40.0% | logic masks merged by cl SHC_3BB0A8C1_0x00514520 | 75.3% | 75.63% spill order -SHC_3BB0A8C1_0x005146D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005146D0 | 40.4% | 47.46% regalloc SHC_3BB0A8C1_0x00514BC0 | 0.0% | Pending From 51aadae10fec129c69af175c1e7e488d94c65cf8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:42:47 +0200 Subject: [PATCH 190/252] reimplement: SHC_3BB0A8C1_0x005029D0 28.49% 34.09% this spilled vs regallo --- .../TileMapState/validateWallBuildPath.cpp | 282 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/validateWallBuildPath.cpp diff --git a/src/OpenSHC/Map/TileMapState/validateWallBuildPath.cpp b/src/OpenSHC/Map/TileMapState/validateWallBuildPath.cpp new file mode 100644 index 000000000..45bf4492f --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/validateWallBuildPath.cpp @@ -0,0 +1,282 @@ + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingFailReasonEnum.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_PLAIN1_AND_FARM; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingFailReasonEnum; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005029D0 + void TileMapState::validateWallBuildPath( + int playerID, uint x1, uint y1, uint x2, uint y2, undefined4 command) + { + int budget = 0; + int overshoot = 2; + int enemyRange; + int searchRange; + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + enemyRange = 0xf; + searchRange = 7; + } else { + enemyRange = 0x1e; + searchRange = 0x1e; + } + this->buildingPlacementFail = FALSE; + this->illegalBuild = TRUE; + this->field118_0x554920 = 0; + if (x1 > 399 || y1 > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y1 * 400 + x1] == 0) { + this->buildingPlacementFail = TRUE; + return; + } + if (x2 > 399 || y2 > 399 || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y2 * 400 + x2] == 0) { + this->buildingPlacementFail = TRUE; + return; + } + + int* translation = &DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; + int tile = *translation + x1; + this->DAT_SomeY = y1; + this->DAT_SomeTile = tile; + if ((short)command == 0x1b) { + /* a stair needs an enclosed wall to lean against, and enough height on it */ + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isTileEnclosedByWallsOrGates, this)(tile, y1) == FALSE) { + return; + } + this->field119_0x554924 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getMaxWallHeightInBrushArea, this)(tile, y1); + if (this->field119_0x554924 < 0x11) { + return; + } + budget = this->field119_0x554924; + } else if ((short)command == 0x1a + && MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isTileEnclosedByWalls, this)(tile, y1) == 0) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x13; + return; + } + + int upY = y1 - y2; + int downY = y2 - y1; + int rightX = x2 - x1; + this->field118_0x554920 = 1; + uint y = y1; + uint x = x1; + int leftX = x1 - x2; + do { + tile = *translation + x; + uint logic = this->LogicLayer[tile]; + if ((logic & (L_PLAIN1_AND_FARM | L_BORDER)) != 0) { + return; + } + if ((logic & (L_SEA | L_BUILDING | L_KEEP_NON_MANOR_HOUSE | L_MARSH | L_MOAT)) != 0) { + return; + } + if (this->BuildingLayer[tile] != 0) { + return; + } + if ((logic & (L_TREE | L_TREE_VARIATION)) != 0 && this->OrganismLayer[tile] != 0 + && this->OrganismLayer[tile] < 2000) { + /* scrub can be built through, a real tree cannot */ + switch (DAT_LandscapeState::instance.trees[this->OrganismLayer[tile]].treeType) { + case (TreeType)5: + case (TreeType)6: + case (TreeType)7: + case (TreeType)8: + case (TreeType)9: + case (TreeType)0xa: + case (TreeType)0xb: + case (TreeType)0xc: + case (TreeType)0xd: + case (TreeType)0xe: + case (TreeType)0x10: + case (TreeType)0x11: + case (TreeType)0x12: + case (TreeType)0x13: + break; + default: + return; + } + } + if ((logic & (L_RIVER | L_FORD)) != 0) { + return; + } + if ((char)logic < 0) { + return; + } + if (this->UnitLayer[tile] != 0 && (logic & L_WALL_OR_GATEHOUSE) == 0 + && DAT_UnitsState::instance.units[(short)this->UnitLayer[tile]].unitType != OpenSHC::Map::Units::UT_CHICKEN) { + return; + } + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, DAT_PathFindingState::ptr)( + playerID, x, y, enemyRange) + != FALSE) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x11; + return; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, DAT_PathFindingState::ptr)( + playerID, x, y, searchRange, -1, -1, -1) + != 0) { + if (this->buildingPlacementFailReason == (BuildingFailReasonEnum)0x12) { + return; + } + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x13; + return; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + int buildRange = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getCastleBuildRangeForMapSize, this)(); + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isTileInRangeOfKeepRange, DAT_PathFindingState::ptr)( + playerID, x, y, buildRange) + != 0) { + if (this->buildingPlacementFailReason == (BuildingFailReasonEnum)0x12) { + return; + } + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x13; + return; + } + } + } + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_EDITOR + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, DAT_PathFindingState::ptr)( + playerID, x, y, 7, -1, -1, -1) + != 0) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x11; + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findSomeSuitableLocationUnk, DAT_PathFindingState::ptr)( + playerID, x, y, 2) + != 0) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x11; + return; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isSignPostWithinDistance, DAT_PathFindingState::ptr)( + x, y, DAT_GameState::instance.mapAndTime.unk_signpostDistance + 5) + != FALSE) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x15; + return; + } + if ((short)command == 0x1a) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isTileEnclosedByWalls, this)(tile, y) == 0) { + this->buildingPlacementFailReason = (BuildingFailReasonEnum)0x13; + return; + } + } else if ((short)command == 0x1b + && (budget < 0x11 || (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0)) { + break; + } + + int stepX = leftX; + if ((int)x < (int)x2) { + stepX = rightX; + } + int stepY = upY; + if ((int)y < (int)y2) { + stepY = downY; + } + if ((short)command == 0x1b) { + if (stepY < stepX) { + if ((int)x < (int)x2) { + leftX = leftX + 1; + x = x + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + x = x - 1; + rightX = rightX + 1; + } + } else if (stepY > 0) { + if ((int)y < (int)y2) { + translation = translation + 3; + upY = upY + 1; + y = y + 1; + downY = downY - 1; + } else { + translation = translation - 3; + upY = upY - 1; + y = y - 1; + downY = downY + 1; + } + } else { + overshoot = overshoot - 1; + } + } else { + if (stepX != 0) { + if ((int)x < (int)x2) { + leftX = leftX + 1; + x = x + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + x = x - 1; + rightX = rightX + 1; + } + } + if (stepY != 0) { + if ((int)y < (int)y2) { + translation = translation + 3; + upY = upY + 1; + y = y + 1; + downY = downY - 1; + } else { + translation = translation - 3; + upY = upY - 1; + y = y - 1; + downY = downY + 1; + } + } + if (x == x2 && y == y2) { + overshoot = overshoot - 1; + } + } + if (budget > 0x10) { + budget = budget - 0x10; + } + } while (x != x2 || y != y2 || overshoot != 0); + this->illegalBuild = FALSE; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index cdaa6509e..936fe67fb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41579,7 +41579,7 @@ SHC_3BB0A8C1_0x00502680 | 19.9% | 20.99% highest/lowest spilled SHC_3BB0A8C1_0x00502950 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005029D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005029D0 | 28.5% | 34.09% this spilled vs regallo SHC_3BB0A8C1_0x00502F14 | 0.0% | Pending From ca232e4ecf774d95d9c224a7fee4360c383ad538 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:45:54 +0200 Subject: [PATCH 191/252] reimplement: SHC_3BB0A8C1_0x00502F30 33.92% 36.78% shared blocks as flags --- src/OpenSHC/Map/TileMapState/placeWalls.cpp | 281 ++++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeWalls.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeWalls.cpp b/src/OpenSHC/Map/TileMapState/placeWalls.cpp new file mode 100644 index 000000000..3d9d5b1ff --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeWalls.cpp @@ -0,0 +1,281 @@ + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/WallAndPitchState.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WallAndPitchState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00502F30 + void TileMapState::placeWalls( + int playerID, uint x1, uint y1, uint x2, uint y2, MappersEnum wallType, int tileCountUnk) + { + int budget = 0; + int wallCount = 0; + int placed = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::validateWallBuildPath, this)(playerID, x1, y1, x2, y2, wallType); + if (this->illegalBuild != FALSE) { + return; + } + + this->constructionTileCount = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getWallTilesThatCanBeBuilt, DAT_GameState::ptr)( + playerID, 4); + int overshoot = 2; + if ((short)wallType == OpenSHC::Commands::M_MAPPER_STAIR) { + budget = this->field119_0x554924; + } + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(OpenSHC::Map::WallAndPitchState_Func::resetWallPlacementInfo, DAT_WallAndPitchState::ptr)(); + } + + int upY = y1 - y2; + int downY = y2 - y1; + int rightX = x2 - x1; + int* translation = &DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; + uint x = x1; + int leftX = x1 - x2; + bool stairAborted = false; + do { + if ((short)wallType == OpenSHC::Commands::M_MAPPER_STAIR && budget < 0x18) { + stairAborted = true; + break; + } + if (tileCountUnk <= placed || this->constructionTileCount < wallCount) { + break; + } + placed++; + int tile = *translation + x; + bool towerNeighbours = false; + if ((short)wallType == OpenSHC::Commands::M_MAPPER_STAIR + && (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0) { + stairAborted = true; + break; + } + /* a wall dragged over a crenel replaces it without counting against the tally */ + bool overCrenel = false; + if ((short)wallType == OpenSHC::Commands::M_MAPPER_WALL && (this->LogicLayer[tile] & L_CRENEL) != 0) { + overCrenel = true; + } + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0 || this->DamageLayer[tile] != 0 || overCrenel) { + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(OpenSHC::Map::WallAndPitchState_Func::addWallPlacementInfoForTile, DAT_WallAndPitchState::ptr)(tile); + } + if (this->DamageLayer[tile] != 0 || overCrenel) { + this->DamageLayer[tile] = 0; + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + if (overCrenel) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_CRENEL | L_CRENEL_VARIATIONUnk) + | L_WALL_OR_GATEHOUSE; + } + } + + bool applyWall = true; + bool updateLinkages = true; + if ((short)wallType == OpenSHC::Commands::M_MAPPER_WALL) { + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x5a; + } else if ((short)wallType == OpenSHC::Commands::M_MAPPER_WOODWALL) { + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x3c; + } else if ((short)wallType == OpenSHC::Commands::M_MAPPER_CRENAL) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_CRENEL; + BOOLEnum onlyTowers = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::hasOnlyTowerNeighborsNoWalls, this)(tile, y1); + if (onlyTowers == FALSE) { + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x62; + } else { + this->HeightLayer[tile] = this->HeightLayer[tile] + 0x44; + } + towerNeighbours = onlyTowers != FALSE; + /* a crenel on an odd tile of one axis carries the alternate variation */ + if (((x & 1) == 0) != ((y1 & 1) == 0)) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_CRENEL_VARIATIONUnk; + } + } else if ((short)wallType == OpenSHC::Commands::M_MAPPER_STAIR) { + int steps = (budget - (int)(uint)this->HeightLayer[tile]) + -0x10; + if (steps > 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_STAIRS; + this->HeightLayer[tile] = this->HeightLayer[tile] + (char)steps; + } else { + applyWall = false; + updateLinkages = overCrenel; + } + } + + if (applyWall && !overCrenel) { + wallCount++; + this->LogicLayer[tile] + = this->LogicLayer[tile] & ~(L_UNKNOWN_WALL_RELATED | L_BOULDERS | L_PEBBLES | L_IRON) + | L_WALL_OR_GATEHOUSE; + if (this->UnitLayer[tile] != 0 + && DAT_UnitsState::instance.units[(short)this->UnitLayer[tile]].unitType == OpenSHC::Map::Units::UT_CHICKEN) { + int unitID = (short)this->UnitLayer[tile]; + DAT_UnitsState::instance.units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + DAT_UnitsState::instance.units[unitID].updateTickTracker = 0; + DAT_UnitsState::instance.units[unitID].disappearFadeAlphaCountdown = 0; + } + if ((this->LogicLayer[tile] & L_PLAIN2_AND_PITCH) != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_PLAIN2_AND_PITCH; + this->HeightLayer[tile] = this->HeightLayer[tile] + 4; + } + if ((this->LogicLayer[tile] & L_TREE) != 0 && this->OrganismLayer[tile] < 2000) { + /* scrub is flattened by the wall, a real tree is left standing */ + switch (DAT_LandscapeState::instance.trees[this->OrganismLayer[tile]].treeType) { + case (TreeType)5: + case (TreeType)6: + case (TreeType)7: + case (TreeType)8: + case (TreeType)9: + case (TreeType)0xa: + case (TreeType)0xb: + case (TreeType)0xc: + case (TreeType)0xd: + case (TreeType)0xe: + case (TreeType)0x10: + case (TreeType)0x11: + case (TreeType)0x12: + case (TreeType)0x13: + DAT_LandscapeState::instance.trees[this->OrganismLayer[tile]].state = 3; + } + } + if ((short)wallType == OpenSHC::Commands::M_MAPPER_WOODWALL || towerNeighbours) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_UNKNOWN_WALL_RELATED; + } + this->WallOwnerLayer[tile] = this->WallOwnerLayer[tile] & 0xf8 | (char)playerID - 1U; + } + if (updateLinkages) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, DAT_PathFindingState::ptr)( + y1, tile); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoat, this)(tile); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, DAT_PathFindingState::ptr)(7, x, y1); + } + } + + int stepX = leftX; + if ((int)x < (int)x2) { + stepX = rightX; + } + int stepY = upY; + if ((int)y1 < (int)y2) { + stepY = downY; + } + if ((short)wallType == OpenSHC::Commands::M_MAPPER_STAIR) { + if (stepY < stepX) { + if ((int)x < (int)x2) { + leftX = leftX + 1; + x = x + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + x = x - 1; + rightX = rightX + 1; + } + } else if (stepY < 1) { + overshoot = overshoot - 1; + } else if ((int)y1 < (int)y2) { + y1 = y1 + 1; + translation = translation + 3; + upY = upY + 1; + downY = downY - 1; + } else { + y1 = y1 - 1; + translation = translation - 3; + upY = upY - 1; + downY = downY + 1; + } + } else { + if (stepX != 0) { + int advance = 1; + if ((int)x < (int)x2) { + leftX = leftX + 1; + rightX = rightX - 1; + } else { + leftX = leftX - 1; + advance = -1; + rightX = rightX + 1; + } + x = x + advance; + } + if (stepY != 0) { + if ((int)y1 < (int)y2) { + y1 = y1 + 1; + translation = translation + 3; + upY = upY + 1; + downY = downY - 1; + } else { + y1 = y1 - 1; + translation = translation - 3; + upY = upY - 1; + downY = downY + 1; + } + } + if (x == x2 && y1 == y2) { + overshoot = overshoot - 1; + } + } + if (budget > 0xf) { + budget = budget - 0x10; + } + } while (x != x2 || y1 != y2 || overshoot != 0); + + int woodCount; + int stoneCount; + if (!stairAborted && (short)wallType == OpenSHC::Commands::M_MAPPER_WOODWALL) { + stoneCount = 0; + woodCount = wallCount; + } else { + woodCount = 0; + stoneCount = wallCount; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processWallBuildingLoss, DAT_BuildingsState::ptr)( + playerID, stoneCount, woodCount, 0); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 936fe67fb..45cc7f606 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41615,7 +41615,7 @@ SHC_3BB0A8C1_0x00502F29 | 0.0% | Pending SHC_3BB0A8C1_0x00502F2A | 0.0% | Pending -SHC_3BB0A8C1_0x00502F30 | 0.0% | Pending +SHC_3BB0A8C1_0x00502F30 | 33.9% | 36.78% shared blocks as flags SHC_3BB0A8C1_0x0050347C | 0.0% | Pending From 85f7f8347c395bb07247c6bcd294175226ed57a7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:49:07 +0200 Subject: [PATCH 192/252] reimplement: SHC_3BB0A8C1_0x00506370 42.13% 44.49% per-arm stores vs share --- .../updateBuildingGraphicsLayer.cpp | 214 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp b/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp new file mode 100644 index 000000000..e326669ea --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp @@ -0,0 +1,214 @@ + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00506370 + void TileMapState::updateBuildingGraphicsLayer(int buildingID) + { + ushort buildingXPos = DAT_BuildingsState::instance.buildings[buildingID].x; + ushort buildingYPos = DAT_BuildingsState::instance.buildings[buildingID].y; + DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 = 0; + if (this->refreshRelatedOne == 0 && DAT_BuildingsState::instance.buildings[buildingID].gfxOffset != 0) { + DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 = 1; + } + int stored = DAT_BuildingsState::instance.buildings[buildingID].currentNumberOfResource - (int)DAT_BuildingsState::instance.buildings[buildingID].someResourceNumber; + + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + index, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + (short)buildingYPos].addXgetTile + + (short)buildingXPos + this->buildingX; + if (this->field93_0x5548c8 != 0) { + /* the placement overlay replaces every building graphic with its outline */ + this->AlphaGFXLayer[tile] = 0; + this->GfxLayer[tile] = ((short)DAT_TerrainDefinedData::instance.BrushSizeArray[DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight + 7] + (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[0x9d]) + - 1; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_STOCKPILE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_QUARRYSTOCKPILE) { + /* a stockpile's pile grows with what is stored on it */ + if (stored < 1) { + this->GfxLayer[tile] = (short)this->buildingRotationRelatedValue + (short)GMTotalPicturesProcessed::instance[0xf] + 4; + } else { + short resource = DAT_BuildingsState::instance.buildings[buildingID].currentStoredResourceType; + short pile; + if (DAT_TerrainDefinedData::instance.field1001_0x8b4[resource] == 2) { + int remaining = DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource - stored; + pile = (short)this->buildingRotationRelatedValue + + ((short)((remaining + (remaining >> 0x1f & 3U)) >> 2) + ((ushort)remaining & 3) * 0xc) + * 4; + } else if (DAT_TerrainDefinedData::instance.field1001_0x8b4[resource] == 0) { + pile = (short)this->buildingRotationRelatedValue + -4 + (short)stored * 4; + } else { + pile = (short)this->buildingRotationRelatedValue + ((short)DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource - (short)stored) * 4; + } + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[0xf] + (short)DAT_TerrainDefinedData::instance.field996_0x84c[resource] + -1 + pile; + } + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_MERCENARYPOST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_BARRACKS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_OUTPOST_EUROPEAN) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR_LEFT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR_RIGHT) { + /* a side door faces along the keep's axis, so its graphic follows the map rotation */ + uint facing = this->mapOrientation; + if (DAT_BuildingsState::instance.buildings[buildingID].orientation == 6 || DAT_BuildingsState::instance.buildings[buildingID].orientation == 2) { + facing = this->mapOrientation + 2U & 0x80000007; + if ((int)facing < 0) { + facing = (facing - 1 | 0xfffffff8) + 1; + } + } + if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { + if (facing == 2 || facing == 6) { + this->GfxLayer[tile] + = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; + } else { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) + - 1; + } + } else if (facing == 2 || facing == 6) { + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset; + } else { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) - 1; + } + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR) { + if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { + if (this->mapOrientation != 2 && this->mapOrientation != 6) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) + - 1; + } else { + this->GfxLayer[tile] + = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; + } + } else { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + - 1; + } + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WOODGATE1) { + int variation; + if (this->mapOrientation == 2 || this->mapOrientation == 6) { + variation = (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0x50) + 0x50; + } else { + variation = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation; + } + if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { + if (variation == 0x50) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; + } else { + this->GfxLayer[tile] + = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset2) + (short)this->buildingRotationRelatedValue) - 1; + } + } else if (variation != 0x50) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset3 + (short)this->buildingRotationRelatedValue) - 1; + } else { + this->GfxLayer[tile] = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + (short)this->buildingRotationRelatedValue) - 1; + } + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_MANORHOUSE) { + int variation = 0x50; + if (this->mapOrientation == 2 || this->mapOrientation == 6) { + variation = 0x51; + } + if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 != 0) { + if (variation == 0x50) { + this->GfxLayer[tile] = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + (short)this->buildingRotationRelatedValue) - 1; + } else { + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)this->buildingRotationRelatedValue + 0x298; + } + } else if (variation == 0x50) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; + } else { + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)this->buildingRotationRelatedValue + 0x236; + } + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + int plank = DAT_TerrainDefinedData::instance.field2467_0x1fec[(int)DAT_BuildingsState::instance.buildings[buildingID].buildingVariation / 2][index]; + if (plank != 0) { + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)plank + 0x61e; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(tile) + == 0) { + this->GfxLayer[tile] = ((byte)this->RandomLayer[tile] & 3) + + (ushort)this->LuminesenceLayer[tile] * 4 + (short)GMTotalPicturesProcessed::instance[2]; + } else { + this->GfxLayer[tile] = ((byte)this->RandomLayer[tile] & 3) + + (this->LuminesenceLayer[tile] + 0x33) * 4 + (short)GMTotalPicturesProcessed::instance[5]; + } + } else if ((DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KILLINGPIT || DAT_BuildingsState::instance.buildings[buildingID].state > 0 + || DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner] + == DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + || DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_EDITOR) + && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { + /* a killing pit is invisible to anyone not on the owner's team */ + if (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0xf) { + if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 != 0) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset + (short)this->buildingRotationRelatedValue) - 1; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingIsVisuallyActive == 0) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) + - 1; + } else { + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].visuallyActiveSpriteID + (short)this->buildingRotationRelatedValue) - 1; + } + this->AlphaGFXLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) + - 1; + } else { + int relative = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation - this->mapOrientation; + if (relative < 0) { + relative = relative + 8; + } + short rotation = (short)relative; + short span; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 8) { + rotation = (short)DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + span = rotation * 8; + } else { + span = (short)DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight; + span = span * span; + } + short sprite; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingIsVisuallyActive == 0) { + sprite = (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; + } else { + sprite = (short)DAT_BuildingsState::instance.buildings[buildingID].visuallyActiveSpriteID; + } + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + sprite + (short)this->buildingRotationRelatedValue + span * rotation) - 1; + this->AlphaGFXLayer[tile] + = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue + span * rotation) - 1; + } + } + index++; + } while (index < this->constructionTileCount); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 45cc7f606..bfbe1f17d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42081,7 +42081,7 @@ SHC_3BB0A8C1_0x00505A10 | 0.0% | Pending SHC_3BB0A8C1_0x005060C0 | 0.0% | Pending -SHC_3BB0A8C1_0x00506370 | 0.0% | Pending +SHC_3BB0A8C1_0x00506370 | 42.1% | 44.49% per-arm stores vs share SHC_3BB0A8C1_0x00506AD0 | 77.9% | buildingType chain tail-merge From 7d9c6df28383762eeef3a868e3514df68bcaa50c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:51:32 +0200 Subject: [PATCH 193/252] reimplement: SHC_3BB0A8C1_0x004F7A80 21.92% 20.69% regalloc, frame size --- .../TileMapState/computeTileLuminescence.cpp | 290 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/computeTileLuminescence.cpp diff --git a/src/OpenSHC/Map/TileMapState/computeTileLuminescence.cpp b/src/OpenSHC/Map/TileMapState/computeTileLuminescence.cpp new file mode 100644 index 000000000..3b05be5df --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/computeTileLuminescence.cpp @@ -0,0 +1,290 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F7A80 + void TileMapState::computeTileLuminescence(int tile, int y) + { + uint logic = this->LogicLayer[tile]; + int shade = 2; + int alongShade = 2; + int acrossShade = 2; + int diagonal = 0; + int opposite = 0; + uint along = 0; + uint across = 0; + if ((logic & (L_BORDER | L_BORDER_EDGE | L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0) { + return; + } + + /* the light comes from one corner of the screen, so the rays turn with the map */ + switch (this->mapOrientation) { + case 0: + diagonal = 5; + opposite = 1; + along = 4; + across = 6; + break; + case 2: + diagonal = 7; + opposite = 3; + along = 6; + across = 0; + break; + case 4: + diagonal = 1; + opposite = 5; + along = 0; + across = 2; + break; + case 6: + diagonal = 3; + opposite = 7; + along = 2; + across = 4; + } + + uint ownHeight = this->HeightLayer[tile]; + if ((logic & L_TREE) != 0) { + int stage = MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::getTreeGrowthTargetStage, DAT_LandscapeState::ptr)( + this->OrganismLayer[tile]); + if (stage > 2) { + shade = stage; + } + } else if ((logic & L_TREE_VARIATION) != 0) { + shade = 5; + } + + /* first ray: along the light's diagonal, shading hardest close to the tile */ + uint height = 0; + int rayTile = tile; + int rayY = y; + uint step = 6; + do { + rayTile = rayTile + this->directionTranslationMatrix[rayY][diagonal]; + rayY = rayY + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[diagonal].int_.yOffset; + if ((this->LogicLayer[rayTile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + if ((this->LogicLayer[rayTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0) { + height = this->HeightLayer[rayTile]; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag3, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + == 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + < 0x10) { + height = this->HeightLayer[rayTile] + 0x10; + } else { + height = (uint)this->HeightLayer[rayTile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]); + } + } + if ((this->LogicLayer[rayTile] & L_TREE) != 0) { + height = height + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::getTreeGrowthTargetStage, DAT_LandscapeState::ptr)( + this->OrganismLayer[rayTile]) + * 7; + } else if ((this->LogicLayer[rayTile] & L_TREE_VARIATION) != 0) { + height = height + 0x28; + } + int rise = height - ownHeight; + uint lit; + if (rise < 1) { + lit = 2; + } else if (rise > 0x12) { + lit = step + 1; + } else if (rise < 3) { + lit = 0; + } else if (rise < 7) { + lit = step + -3; + } else if (rise < 0xb) { + lit = step + -2; + } else if (rise < 0xf) { + lit = step + -1; + } else { + lit = step; + } + if (shade < (int)lit) { + shade = lit; + } + step = step - 1; + } while ((int)step > 1); + + /* second ray: one cardinal step off the diagonal */ + rayTile = this->directionTranslationMatrix[y][along] + tile; + rayY = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[along].int_.yOffset + y; + along = 4; + uint sampled = height; + do { + if ((this->LogicLayer[rayTile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + if ((this->LogicLayer[rayTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0) { + sampled = this->HeightLayer[rayTile]; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag3, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + == 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + < 0x10) { + sampled = this->HeightLayer[rayTile] + 0x10; + } else { + sampled = (uint)this->HeightLayer[rayTile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]); + } + } + if ((this->LogicLayer[rayTile] & L_TREE) != 0) { + sampled = sampled + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::getTreeGrowthTargetStage, DAT_LandscapeState::ptr)( + this->OrganismLayer[rayTile]) + * 7; + } else if ((this->LogicLayer[rayTile] & L_TREE_VARIATION) != 0) { + sampled = sampled + 0x28; + } + int rise = sampled - ownHeight; + if (rise < 1) { + height = 2; + } else if (rise > 0x12) { + height = along + 1; + } else if (rise < 7) { + height = 0; + } else if (rise < 0xd) { + height = along - 1; + } else { + height = along; + } + if (alongShade < (int)height) { + alongShade = height; + } + rayTile = rayTile + this->directionTranslationMatrix[rayY][diagonal]; + along = along - 1; + rayY = rayY + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[diagonal].int_.yOffset; + } while (along < 0x80000000); + + /* third ray: the same, one cardinal step the other way */ + rayTile = this->directionTranslationMatrix[y][across] + tile; + rayY = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[across].int_.yOffset + y; + across = 4; + do { + if ((this->LogicLayer[rayTile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + if ((this->LogicLayer[rayTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0) { + sampled = this->HeightLayer[rayTile]; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag3, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + == 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]) + < 0x10) { + sampled = this->HeightLayer[rayTile] + 0x10; + } else { + sampled = (uint)this->HeightLayer[rayTile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[rayTile]); + } + } + if ((this->LogicLayer[rayTile] & L_TREE) != 0) { + sampled = sampled + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::getTreeGrowthTargetStage, DAT_LandscapeState::ptr)( + this->OrganismLayer[rayTile]) + * 7; + } else if ((this->LogicLayer[rayTile] & L_TREE_VARIATION) != 0) { + sampled = sampled + 0x28; + } + int rise = sampled - ownHeight; + if (rise < 1) { + height = 2; + } else if (rise > 0x12) { + height = across + 1; + } else if (rise < 7) { + height = 0; + } else if (rise < 0xd) { + height = across - 1; + } else { + height = across; + } + if (acrossShade < (int)height) { + acrossShade = height; + } + rayTile = rayTile + this->directionTranslationMatrix[rayY][diagonal]; + across = across - 1; + rayY = rayY + DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[diagonal].int_.yOffset; + } while (across < 0x80000000); + + if (shade + -2 < (int)((acrossShade - 4) + alongShade)) { + shade = (acrossShade - 2) + alongShade; + if (shade > 6) { + shade = 7; + } + } else if (shade == 2) { + /* nothing casts onto the tile, so shade it by the slope it sits on */ + int diagonalTile = this->directionTranslationMatrix[y][diagonal] + tile; + uint lightSide = ownHeight; + if ((this->LogicLayer[diagonalTile] & (L_BORDER | L_BORDER_EDGE)) == 0) { + if ((this->LogicLayer[diagonalTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0) { + lightSide = this->HeightLayer[diagonalTile]; + } else { + lightSide = sampled; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag3, DAT_BuildingsState::ptr)( + this->BuildingLayer[diagonalTile]) + == 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, DAT_BuildingsState::ptr)( + this->BuildingLayer[diagonalTile]) + < 0x10) { + lightSide = this->HeightLayer[diagonalTile] + 0x10; + } else { + lightSide = (uint)this->HeightLayer[diagonalTile] + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(this->BuildingLayer[diagonalTile]); + } + } + } + } + int oppositeTile = this->directionTranslationMatrix[y][opposite] + tile; + uint darkSide = ownHeight; + if ((this->LogicLayer[oppositeTile] & (L_BORDER | L_BORDER_EDGE)) == 0) { + darkSide = this->HeightLayer[oppositeTile]; + } + char slope = (int)lightSide < (int)(ownHeight - 4); + if (ownHeight + 4 < darkSide) { + slope = slope + '\x01'; + } + if ((this->LogicLayer[tile] & L_MOAT) == 0) { + if (slope == '\x01') { + shade = 1; + } else if (slope == '\x02') { + shade = 0; + } + } + } + this->LuminesenceLayer[tile] = (uchar)shade; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bfbe1f17d..d10a3bdb7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38769,7 +38769,7 @@ SHC_3BB0A8C1_0x004F7170 | 0.0% | Pending SHC_3BB0A8C1_0x004F79D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F7A80 | 0.0% | Pending +SHC_3BB0A8C1_0x004F7A80 | 21.9% | 20.69% regalloc, frame size SHC_3BB0A8C1_0x004F7E50 | 0.0% | Pending From 9f7cb125e71572ef67ec955b06d67015ec9c63b8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:53:33 +0200 Subject: [PATCH 194/252] reimplement: SHC_3BB0A8C1_0x004FF080 27.31% 27.06% regalloc --- .../TileMapState/updateMacroLayerRelated2.cpp | 222 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateMacroLayerRelated2.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated2.cpp b/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated2.cpp new file mode 100644 index 000000000..8e202f07e --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateMacroLayerRelated2.cpp @@ -0,0 +1,222 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_SEA; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004FF080 + void TileMapState::updateMacroLayerRelated2() + { + int startRow; + startRow = DAT_PathFindingState::instance.mappingYRelated % 10; + for (int block = this->someIndex; block <= this->someLimit; block++) { + for (int sub = this->someYLike; sub <= this->someYLikeLimit; sub++) { + if (this->mapping40x40[block][sub] == 0) { + continue; + } + for (int row = startRow; row < 10; row++) { + this->DAT_SomeY = block * 10 + row; + this->DAT_SomeX = sub * 10; + int group = 2; + do { + if ((uint)this->DAT_SomeX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + this->DAT_SomeX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + this->DAT_SomeX; + if (this->ChangedLayer[this->DAT_SomeTile] != 0 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->ChangedLayer[this->DAT_SomeTile] != 0 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->ChangedLayer[this->DAT_SomeTile] != 0 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->ChangedLayer[this->DAT_SomeTile] != 0 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->ChangedLayer[this->DAT_SomeTile] != 0 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + this->MacroLayer[this->DAT_SomeTile] = 0x800; + } + } + this->DAT_SomeX = nextX; + } + this->DAT_SomeX = this->DAT_SomeX + 1; + group = group + -1; + } while (group != 0); + } + startRow = 0; + } + } + + startRow = DAT_PathFindingState::instance.mappingYRelated % 10; + for (int block = this->someIndex; block <= this->someLimit; block++) { + for (int sub = this->someYLike; sub <= this->someYLikeLimit; sub++) { + if (this->mapping40x40[block][sub] == 0) { + continue; + } + for (int row = startRow; row < 10; row++) { + this->DAT_SomeY = block * 10 + row; + this->DAT_SomeX = sub * 10; + int column = 10; + do { + if ((uint)this->DAT_SomeX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + this->DAT_SomeX] != 0) { + this->DAT_SomeTile = this->DAT_SomeX + + DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800 + && (this->LogicLayer[this->DAT_SomeTile] & L_SEA) != 0) { + ushort random = this->RandomLayer[this->DAT_SomeTile]; + int corner = this->DAT_SomeTile + - DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile; + /* a wave sprite only fits where all sixteen of its tiles are still marked */ + bool complete = true; + for (int i = 0; i < 0x10; i++) { + if (this->MacroLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2292_0x19d4[i].y + + this->DAT_SomeY] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2292_0x19d4[i].x + corner] + != 0x800) { + complete = false; + break; + } + } + if (complete) { + for (int i = 0; i < 0x10; i++) { + this->MacroLayer[DAT_ViewportRenderState::instance + .translationMatrix[DAT_TerrainDefinedData::instance.field2292_0x19d4[i].y + + this->DAT_SomeY] + .addXgetTile + + DAT_TerrainDefinedData::instance.field2292_0x19d4[i].x + corner] + = (ushort)(byte)random * 0x1000 + 0x10 + (short)(i << 6); + } + } + } + } + this->DAT_SomeX = this->DAT_SomeX + 1; + column = column + -1; + } while (column != 0); + } + startRow = 0; + } + } + + startRow = DAT_PathFindingState::instance.mappingYRelated % 10; + for (int block = this->someIndex; block <= this->someLimit; block++) { + for (int sub = this->someYLike; sub <= this->someYLikeLimit; sub++) { + if (this->mapping40x40[block][sub] == 0) { + continue; + } + for (int row = startRow; row < 10; row++) { + this->DAT_SomeY = block * 10 + row; + this->DAT_SomeX = sub * 10; + int group = 2; + do { + if ((uint)this->DAT_SomeX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + this->DAT_SomeX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + this->DAT_SomeX; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + this->DAT_SomeX = nextX; + } + { + uint nextX = this->DAT_SomeX + 1; + if (nextX < 400 && (uint)this->DAT_SomeY < 400 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[this->DAT_SomeY * 400 + nextX] != 0) { + this->DAT_SomeTile = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_SomeY].addXgetTile + nextX; + if (this->MacroLayer[this->DAT_SomeTile] == 0x800) { + this->MacroLayer[this->DAT_SomeTile] = 2; + } + } + this->DAT_SomeX = nextX; + } + this->DAT_SomeX = this->DAT_SomeX + 1; + group = group + -1; + } while (group != 0); + } + startRow = 0; + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d10a3bdb7..8921d6763 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41099,7 +41099,7 @@ SHC_3BB0A8C1_0x004FC9E0 | 64.5% | Od stack slot order differs SHC_3BB0A8C1_0x004FDB00 | 56.3% | Od stack slot order differs -SHC_3BB0A8C1_0x004FF080 | 0.0% | Pending +SHC_3BB0A8C1_0x004FF080 | 27.3% | 27.06% regalloc SHC_3BB0A8C1_0x004FF420 | 0.0% | Pending From ddcd6b67dd320daac2bf2a6694bf80f05f14196d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 29 Sep 2026 23:56:18 +0200 Subject: [PATCH 195/252] reimplement: SHC_3BB0A8C1_0x004F70F0 27.21% 28.62% regalloc --- .../updateLogicalTileMapRelatedSections.cpp | 341 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateLogicalTileMapRelatedSections.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateLogicalTileMapRelatedSections.cpp b/src/OpenSHC/Map/TileMapState/updateLogicalTileMapRelatedSections.cpp new file mode 100644 index 000000000..b353cfbb4 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateLogicalTileMapRelatedSections.cpp @@ -0,0 +1,341 @@ +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L2_BEACH; + using OpenSHC::Map::LogicHelpers::L2_EARTH_AND_STONES; + using OpenSHC::Map::LogicHelpers::L2_OASIS_GRASS; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_HIGH; + using OpenSHC::Map::LogicHelpers::L2_PLATEAU_MEDIUM; + using OpenSHC::Map::LogicHelpers::L2_SCRUB; + using OpenSHC::Map::LogicHelpers::L2_STONES_OR_DRIVEN_SANDUnk; + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_DEFAULT_EARTH_OR_TEXTURE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_HOP; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_WHEAT; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_TREE_VARIATION; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Map::Buildings::BuildingType; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004F70F0 + void TileMapState::updateLogicalTileMapRelatedSections() + { + if (this->forceUpdateLogicalAndMiscDisplayLayers == 0) { + return; + } + this->forceUpdateLogicalAndMiscDisplayLayers = 0; + int tile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_PathFindingState::instance.mappingYRelated] + .firstTileOfRow; + DAT_BuildingsState::instance.field34_0x18e074 = 1; + for (int row = DAT_PathFindingState::instance.mappingYRelated; + row < 400 && row <= DAT_PathFindingState::instance.yLimit; row++) { + for (int column = 0; column < this->yArray1[row]; column++, tile++) { + if ((this->LogicLayer[tile] & (L_BORDER | L_BORDER_EDGE)) != 0 + || this->ChangedLayer[tile] == 0) { + continue; + } + + uint height = this->HeightLayer[tile]; + int screenY = this->heightBasedScreenYOffset[height]; + this->ShowHiLayer[tile] = '\0'; + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffef; + /* whether the tile draws its own texture or the default earth */ + if (height == 0) { + if (((this->LogicLayer[tile] & L_RIVER) == 0 + && (this->Logic2Layer[tile] & L2_BEACH) != 0) + || (this->LogicLayer[tile] & L_MOAT) != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_DEFAULT_EARTH_OR_TEXTURE; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_DEFAULT_EARTH_OR_TEXTURE; + } + } else if (height < 9) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_DEFAULT_EARTH_OR_TEXTURE; + } else if ((this->Logic2Layer[tile] & L2_PLATEAU_MEDIUM) != 0 + || (this->Logic2Layer[tile] & L2_PLATEAU_HIGH) != 0 + || (this->Logic2Layer[tile] & L2_EARTH_AND_STONES) != 0 + || (this->Logic2Layer[tile] & L2_OASIS_GRASS) != 0 + || (this->Logic2Layer[tile] & L2_SCRUB) != 0 + || (char)this->Logic2Layer[tile] < '\0' + || (this->Logic2Layer[tile] & L2_STONES_OR_DRIVEN_SANDUnk) != 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] | L_DEFAULT_EARTH_OR_TEXTURE; + } else { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_DEFAULT_EARTH_OR_TEXTURE; + } + + /* a tile level with all eight neighbours keeps its texture */ + for (int i = 0; i < 8; i++) { + int neighbour = this->directionTranslationMatrix[row][i] + tile; + if ((height > 8 || this->HeightLayer[neighbour] == 0) + && height != this->HeightLayer[neighbour]) { + if ((this->LogicLayer[neighbour] & (L_RIVER | L_MOAT)) == 0) { + this->LogicLayer[tile] = this->LogicLayer[tile] & ~L_DEFAULT_EARTH_OR_TEXTURE; + } + break; + } + } + if (this->BuildingLayer[tile] != 0 + && DAT_BuildingsState::instance.buildings[this->BuildingLayer[tile]].buildingType + == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x10; + } + + if (this->field93_0x5548c8 == 0) { + /* look up the light's diagonal for anything standing high enough to shadow us */ + int walkTile = tile; + int* direction = this->directionTranslationMatrix[row] + this->field84_0x5548a4; + bool shadowed = false; + for (int depth = 0; depth < 0x80; depth = depth + 0x10) { + walkTile = walkTile + *direction; + if ((this->LogicLayer[walkTile] & (L_BORDER | L_BORDER_EDGE)) != 0) { + break; + } + if (screenY <= (this->heightBasedScreenYOffset[this->HeightLayer[walkTile]] - depth) + -0x10) { + this->ShowHiLayer[tile] = 0xff; + shadowed = true; + break; + } + direction = direction + this->field88_0x5548b4 * 8; + } + if (height == 0 || shadowed) { + continue; + } + } else { + this->ShowHiLayer[tile] = '\b'; + } + + bool occluded = true; + if ((this->LogicLayer[tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 + && (this->LogicLayer[tile] & L_TREE_VARIATION) == 0 + && (this->LogicLayer[tile] & L_FARM_FIELD_WHEAT) == 0 + && (this->LogicLayer[tile] & L_FARM_FIELD_HOP) == 0 + && (this->LogicLayer[tile] & L_CRENEL) == 0 + && (this->LogicLayer[tile] & L_STAIRS) == 0) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x10; + occluded = false; + } + for (int i = 0; i < 8; i++) { + int neighbour = this->directionTranslationMatrix[row][i] + tile; + if ((height > 8 && height != this->HeightLayer[neighbour]) + || (this->LogicLayer[neighbour] & L_TREE_VARIATION) != 0) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffef; + break; + } + if ((this->LogicLayer[neighbour] & L_FARM_FIELD_WHEAT) != 0) { + occluded = true; + } + if ((this->LogicLayer[neighbour] & L_FARM_FIELD_HOP) != 0) { + occluded = true; + } + } + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfffc; + + bool stepLeft = false; + bool stepRight = false; + int shadowTile = this->directionTranslationMatrix[row][this->field84_0x5548a4] + tile; + int lowest = 0xfa; + if (this->heightBasedScreenYOffset[this->HeightLayer[shadowTile]] < 0xfa) { + lowest = this->heightBasedScreenYOffset[this->HeightLayer[shadowTile]]; + } + int nearly = screenY + 2; + if (nearly < this->heightBasedScreenYOffset[this->HeightLayer[shadowTile]]) { + occluded = true; + } + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + if ((this->LogicLayer[shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[shadowTile]) + != 0) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[row][this->field86_0x5548ac] + tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[row][this->field86_0x5548ac] + tile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[row][this->field86_0x5548ac] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[row][this->field86_0x5548ac] + tile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[row][this->field85_0x5548a8] + tile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[row][this->field85_0x5548a8] + tile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[row][this->field85_0x5548a8] + tile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[row][this->field85_0x5548a8] + tile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field86_0x5548ac] + shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field86_0x5548ac] + shadowTile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field86_0x5548ac] + shadowTile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field86_0x5548ac] + shadowTile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field85_0x5548a8] + shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field85_0x5548a8] + shadowTile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field85_0x5548a8] + shadowTile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field85_0x5548a8] + shadowTile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + shadowTile = shadowTile + + this->directionTranslationMatrix[this->field88_0x5548b4 + row][this->field84_0x5548a4]; + if ((this->LogicLayer[shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[shadowTile]) + != 0) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field86_0x5548ac] + shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field86_0x5548ac] + shadowTile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field86_0x5548ac] + shadowTile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field86_0x5548ac] + shadowTile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + if (((this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field85_0x5548a8] + shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field85_0x5548a8] + shadowTile]) + != 0) + || ((this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field85_0x5548a8] + shadowTile] & L_WALL_OR_GATEHOUSE) != 0 + && (this->LogicLayer[this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field85_0x5548a8] + shadowTile] & L_STOCKPILEUnk) == 0)) { + occluded = true; + } + shadowTile = shadowTile + + this->directionTranslationMatrix[row + this->field88_0x5548b4 * 2][this->field84_0x5548a4]; + if ((this->LogicLayer[shadowTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[shadowTile]) + != 0) { + occluded = true; + } + } else { + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[shadowTile]].flag2 != 0) { + occluded = true; + } + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[shadowTile]].buildingType + == OpenSHC::Map::Buildings::BT_STOCKPILE) { + occluded = true; + } + if (DAT_BuildingsState::instance + .buildings[this->BuildingLayer[this->directionTranslationMatrix + [this->field88_0x5548b4 + row] + [this->field84_0x5548a4] + + shadowTile]] + .flag2 + != 0) { + occluded = true; + } + } + + int leftTile = this->directionTranslationMatrix[row][this->field86_0x5548ac] + tile; + if (this->heightBasedScreenYOffset[this->HeightLayer[leftTile]] < lowest) { + lowest = this->heightBasedScreenYOffset[this->HeightLayer[leftTile]]; + } + if (screenY <= this->heightBasedScreenYOffset[this->HeightLayer[leftTile]]) { + stepLeft = true; + if (nearly < this->heightBasedScreenYOffset[this->HeightLayer[leftTile]]) { + occluded = true; + } + } + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + if ((this->LogicLayer[leftTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[leftTile]) + != 0) { + occluded = true; + } + } else { + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[leftTile]].flag2 != 0) { + occluded = true; + } + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[leftTile]].buildingType + == OpenSHC::Map::Buildings::BT_STOCKPILE) { + occluded = true; + } + } + + int rightTile = this->directionTranslationMatrix[row][this->field85_0x5548a8] + tile; + if (this->heightBasedScreenYOffset[this->HeightLayer[rightTile]] < lowest) { + lowest = this->heightBasedScreenYOffset[this->HeightLayer[rightTile]]; + } + if (screenY <= this->heightBasedScreenYOffset[this->HeightLayer[rightTile]]) { + stepRight = true; + if (nearly < this->heightBasedScreenYOffset[this->HeightLayer[rightTile]]) { + occluded = true; + } + } + bool clear; + if ((this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) == 0) { + if ((this->LogicLayer[tile] & L_KEEP_NON_MANOR_HOUSE) != 0 + || (this->LogicLayer[rightTile] & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 + || MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getBuildingFlag1, DAT_BuildingsState::ptr)( + this->BuildingLayer[rightTile]) + == 0) { + clear = occluded; + } else { + clear = true; + } + } else { + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[rightTile]].flag2 != 0) { + occluded = true; + } + if (DAT_BuildingsState::instance.buildings[this->BuildingLayer[rightTile]].buildingType + == OpenSHC::Map::Buildings::BT_STOCKPILE) { + clear = true; + } else { + clear = occluded; + } + } + if (clear) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xffef; + } else { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 0x10; + } + + if (lowest < screenY) { + if (this->field93_0x5548c8 == 0) { + this->ShowHiLayer[tile] = (char)screenY - (char)lowest; + } + if ((this->LogicLayer[tile] & L_SEA) == 0) { + if (stepLeft) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 1; + } + if (stepRight) { + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] | 2; + } + } + } + } + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8921d6763..c924506e6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -38761,7 +38761,7 @@ SHC_3BB0A8C1_0x004F70D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004F70E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004F70F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004F70F0 | 27.2% | 28.62% regalloc SHC_3BB0A8C1_0x004F7140 | 0.0% | Pending From 8e06bec0158ffc55ed6fc06d741657e70ef616c4 Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:03:12 +0200 Subject: [PATCH 196/252] reimplement: SHC_3BB0A8C1_0x005162D0 35.93% 60.66% dispatch jump table, ca --- .../Map/TileMapState/placeBuilding.cpp | 330 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/placeBuilding.cpp diff --git a/src/OpenSHC/Map/TileMapState/placeBuilding.cpp b/src/OpenSHC/Map/TileMapState/placeBuilding.cpp new file mode 100644 index 000000000..94f609fa3 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/placeBuilding.cpp @@ -0,0 +1,330 @@ + +#include "OpenSHC/Game.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/WallAndPitchState.func.hpp" +#include "OpenSHC/UI/Helpers.func.hpp" +#include "OpenSHC/UI/MinimapViewState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_MinimapViewState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WallAndPitchState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_MOAT_DUG_OR_PLANNED; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_TREE; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005162D0 + void TileMapState::placeBuilding( + PlayerID playerID, int x, int y, MappersEnum cbt, int buildingSize, int buildingOrientation) + { + MappersEnum command = (MappersEnum)(short)cbt; + int pitchDitchID = 0; + if (this->field122_0x554930 == 0) { + if (buildingOrientation == 0xf) { + this->DAT_TempBuildingRotation = 0; + } else { + this->DAT_TempBuildingRotation = buildingOrientation / 2; + } + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::checkBuildingCanBePlacedHere, this)(playerID, x, y, cbt, buildingSize); + if (this->buildingPlacementFail != FALSE) { + return; + } + } + this->field122_0x554930 = 0; + + BuildingType buildingType = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(command); + short shortType = (short)buildingType; + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CRUSADER_TUTORIAL) { + if (MACRO_CALL(OpenSHC::Game_Func::Tutorial_IsActionAllowed)(2, (short)shortType) == FALSE) { + MACRO_CALL(OpenSHC::UI::Helpers_Func::SetTutorialHintActiveWithTimestamp)(); + return; + } + MACRO_CALL(OpenSHC::UI::Helpers_Func::SetTutorialBuildingActionState)( + 7, (BuildingType)(int)(short)shortType); + } + + /* clear whatever the footprint was before the building goes down */ + int index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingSize); + int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + y].addXgetTile + + this->buildingX + x; + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SIEGE_THAT + && (this->LogicLayer[tile] & L_WALL_OR_GATEHOUSE) != 0) { + DAT_GameState::instance.playerDataArray[playerID].startResources[4] + = DAT_GameState::instance.playerDataArray[playerID].startResources[4] + 1; + } + if ((this->LogicLayer[tile] & L_ROCKY) != 0 && this->OrganismLayer[tile] > 1999) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeRock, DAT_LandscapeState::ptr)( + this->OrganismLayer[tile] - 2000); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingSize); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(8, this->buildingX + x, this->buildingY + y); + } + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_CRENEL_VARIATIONUnk | L_UNKNOWN_WALL_RELATED | L_STAIRS | L_CRENEL | L_WALL_OR_GATEHOUSE + | L_PLAIN2_AND_PITCH); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->DamageLayer[tile] = 0; + if ((this->LogicLayer[tile] & L_TREE) != 0 && this->OrganismLayer[tile] < 2000) { + /* every tree goes, scrub or not; only the reported reason differs */ + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + this->OrganismLayer[tile]); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(3, x, y); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingSize); + } + if ((short)this->UnitLayer[tile] != 0) { + /* a unit standing where a walkable building goes is left alone */ + switch (shortType) { + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_DRAWBRIDGE: + case OpenSHC::Map::Buildings::BT_CAMPFIRE: + case OpenSHC::Map::Buildings::BT_PARADEGROUND: + case OpenSHC::Map::Buildings::BT_CAMPGROUND: + case OpenSHC::Map::Buildings::BT_PARADEGROUND2: + case OpenSHC::Map::Buildings::BT_PARADEGROUND3: + case OpenSHC::Map::Buildings::BT_PARADEGROUND4: + case OpenSHC::Map::Buildings::BT_PARADEGROUND5: + case OpenSHC::Map::Buildings::BT_KILLINGPIT: + case OpenSHC::Map::Buildings::BT_PITCHDITCH: + case OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + break; + default: + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::deleteUnit, DAT_UnitsState::ptr)( + (short)this->UnitLayer[tile]); + } + } + if ((this->LogicLayer[tile] & (L_MOAT | L_MOAT_DUG_OR_PLANNED)) != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::clearMoatDataAtTile, this)(this->buildingX + x, this->buildingY + y); + this->LogicLayer[tile] = this->LogicLayer[tile] & ~(L_MOAT | L_MOAT_DUG_OR_PLANNED); + } + this->MiscDisplayLayer[tile] = this->MiscDisplayLayer[tile] & 0xfc3f; + index++; + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + } while (index < this->constructionTileCount); + + /* the building sits at the middle of the heights it covers */ + uint highest = 0; + uint lowest = 1000; + index = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(index, buildingSize); + uint tileHeight = this->HeightLayer[DAT_ViewportRenderState::instance + .translationMatrix[this->buildingY + y] + .addXgetTile + + this->buildingX + x]; + if (highest < tileHeight) { + highest = tileHeight; + } + if (tileHeight < lowest) { + lowest = tileHeight; + } + index++; + } while (index < this->constructionTileCount); + int averageHeight = (highest - lowest) / 2 + lowest; + + if (shortType == OpenSHC::Map::Buildings::BT_TUNNEL && playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::playTunnelerCommandSpeech, DAT_TribesState::ptr)(); + } + + switch ((int)shortType) { + case OpenSHC::Map::Buildings::BT_MERCENARYPOST: + case OpenSHC::Map::Buildings::BT_BARRACKS: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBarracks, this)(playerID, x, (int*)y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_STOCKPILE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeStockpile, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + default: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeWorkshopOrHovel, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_QUARRY: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeQuarry, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_ENGINEERSGUILD: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeEngineersguild, this)(playerID, (int*)x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_TUNNELERSGUILD: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeTunnelersguild, this)(playerID, (int*)x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_OILSMELTER: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeOilsmelter, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_WHEATFARM: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeWheatfarm, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_HOPFARM: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeHopfarm, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_APPLEFARM: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeApplefarm, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, (int*)averageHeight); + break; + case OpenSHC::Map::Buildings::BT_DAIRYFARM: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeDairyfarm, this)(playerID, x, y, buildingType, buildingSize, (int*)buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeGatehouseLarge, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeGatehouseSmall, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_DRAWBRIDGE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeDrawbridge, this)(playerID, x, y, buildingType, buildingSize, (int*)buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_FIREBALLISTA: + case OpenSHC::Map::Buildings::BT_CATAPULT: + case OpenSHC::Map::Buildings::BT_TREBUCHET: + case OpenSHC::Map::Buildings::BT_BATTERINGRAM: + case OpenSHC::Map::Buildings::BT_SIEGETOWER: + case OpenSHC::Map::Buildings::BT_SHIELD: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeSiegeTent, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_KILLINGPIT: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeKillingPit, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeSiegetowerPlaced, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeTower, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_UNKNOWN1: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::stampBuildingOntoTileMap, this)(playerID, x, y, buildingType, + command + ~OpenSHC::Commands::M_MAPPER_MP_KEEP8, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_MANORHOUSE: + case OpenSHC::Map::Buildings::BT_STONEKEEP: + case OpenSHC::Map::Buildings::BT_STRONGHOLD: + case OpenSHC::Map::Buildings::BT_KEEPFOUR: + case OpenSHC::Map::Buildings::BT_KEEPFIVE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeKeep, this)(playerID, x, y, buildingType, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_WOODGATE1: + break; + case OpenSHC::Map::Buildings::BT_PITCHDITCH: + pitchDitchID = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePitchDitch, this)(playerID, x, y); + break; + case OpenSHC::Map::Buildings::BT_GARDEN: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePositiveFearfactor, this)(playerID, x, y, buildingType, + command - OpenSHC::Commands::M_MAPPER_GARDEN1, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_CESSPIT: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePositiveFearfactor, this)(playerID, x, y, buildingType, + command - OpenSHC::Commands::M_MAPPER_CESS_PIT1, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_STATUE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePositiveFearfactor, this)(playerID, x, y, buildingType, + command - OpenSHC::Commands::M_MAPPER_STATUE1, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_SHRINE: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePositiveFearfactor, this)(playerID, x, y, buildingType, + command - OpenSHC::Commands::M_MAPPER_SHRINE1, buildingSize, buildingOrientation, averageHeight); + break; + case OpenSHC::Map::Buildings::BT_POND: + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placePositiveFearfactor, this)(playerID, x, y, buildingType, + command - OpenSHC::Commands::M_MAPPER_POND1, buildingSize, buildingOrientation, averageHeight); + break; + } + + if (playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (shortType != OpenSHC::Map::Buildings::BT_PITCHDITCH) { + MACRO_CALL_MEMBER(OpenSHC::Map::WallAndPitchState_Func::startBuildingDestructionConfirmation, + DAT_WallAndPitchState::ptr)(this->placedBuildingID); + } else if (pitchDitchID != 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::WallAndPitchState_Func::placePitchDitch, DAT_WallAndPitchState::ptr)(pitchDitchID); + } + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, (BuildingType)(int)(short)shortType, 0); + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func:: + hasLessWoodThanTheCostOfAWoodcuttersHutAndNoWoodcutters, + DAT_BuildingsState::ptr)(playerID, (int)(short)shortType) + != 0) { + DAT_BuildingsState::instance.buildings[this->placedBuildingID].field203_0x288 = 1; + } + MACRO_CALL_MEMBER(OpenSHC::UI::MinimapViewState_Func::triggerMinimapRedraw, DAT_MinimapViewState::ptr)(1); + int radius; + if (buildingSize < 6) { + radius = 9; + } else { + radius = buildingSize + 5; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(radius, x, y); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + this->forceUpdateMacroLayerFlag = 1; + this->field68_0x55487c = 200; + } + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c924506e6..cd83632a6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -44777,7 +44777,7 @@ SHC_3BB0A8C1_0x00515F40 | 69.9% | Style pass, asm differs SHC_3BB0A8C1_0x005160C0 | 37.6% | 48.02% global instance base -SHC_3BB0A8C1_0x005162D0 | 0.0% | Pending +SHC_3BB0A8C1_0x005162D0 | 35.9% | 60.66% dispatch jump table, ca SHC_3BB0A8C1_0x00516A64 | 0.0% | Pending From 4f3ade3e31b3508632eb9770cd13990ac50d4146 Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:08:41 +0200 Subject: [PATCH 197/252] reimplement: SHC_3BB0A8C1_0x00517790 42.52% 42.52% shared destroy body as --- ...rocessEntityDamageToBuildingCollateral.cpp | 381 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateral.cpp diff --git a/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateral.cpp b/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateral.cpp new file mode 100644 index 000000000..42143523d --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/processEntityDamageToBuildingCollateral.cpp @@ -0,0 +1,381 @@ + +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Entities.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AICState.hpp" +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Buildings::BuildingLogicalState; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Entities::EntityType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00517790 + void TileMapState::processEntityDamageToBuildingCollateral( + int tile, uint x, uint y, int damage, int playerID, undefined4 unused, int unitID) + { + uint baseY = y; + int baseTile = tile; + /* a negative player id is a request to spare that player's own team */ + bool spareOwnTeam = false; + if (playerID < 0) { + playerID = -playerID; + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + spareOwnTeam = true; + } + } + + for (int index = 0; index < 9; index++) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getTileForBrush, this)( + 0, index, &tile, (int*)&y, baseTile, baseY); + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 && this->BuildingLayer[tile] == 0) { + /* bare wall: grind its height down towards the ground it stands on */ + if ((logic & L_WALL_OR_GATEHOUSE) == 0 || (logic & L_STOCKPILEUnk) != 0) { + continue; + } + uint wallOwner = this->WallOwnerLayer[tile] & 7; + if (spareOwnTeam && DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[wallOwner + 1]) { + continue; + } + DAT_GameState::instance.playerDataArray[wallOwner + 1].defensesDamagedByPlayer = (short)playerID; + if (unitID != 0) { + if (DAT_GameState::instance.mapAndTime.playerTeams[wallOwner + 1] == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + = DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + 1; + } else { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk = 0; + } + } + DAT_GameCore::instance.cowPoisonTrackerUnk + = DAT_GameCore::instance.cowPoisonTrackerUnk + damage * 10; + for (int hit = 0; hit < damage; hit++) { + if (this->HeightLayer[tile] <= this->DefaultHeightLayer[tile]) { + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, + DAT_EntityState::ptr)(tile); + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_CRENEL_VARIATIONUnk | L_UNKNOWN_WALL_RELATED | L_STAIRS | L_CRENEL + | L_PLAIN2_AND_PITCH); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->DamageLayer[tile] = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(y, tile); + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + break; + } + this->HeightLayer[tile] = this->HeightLayer[tile] - 1; + if ((char)this->DamageLayer[tile] < 200) { + this->DamageLayer[tile] = this->DamageLayer[tile] + 1; + } + } + continue; + } + + int buildingID = this->BuildingLayer[tile]; + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == (BuildingLogicalState)0 || DAT_BuildingsState::instance.buildings[buildingID].logicalState == OpenSHC::Map::Buildings::BLS_REMOVE) { + continue; + } + short health = DAT_BuildingsState::instance.buildings[buildingID].currentHealth; + if (health == 0) { + continue; + } + int buildingType = (short)DAT_BuildingsState::instance.buildings[buildingID].buildingType; + if (DAT_BuildingDefinedData::instance.BuildingTypeHasHealth[buildingType] == 0) { + continue; + } + if ((logic & 0xf000000) != 0 || (logic & L_STOCKPILEUnk) != 0) { + continue; + } + if (spareOwnTeam && DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner]) { + continue; + } + + short newHealth = health - (short)damage; + DAT_GameCore::instance.cowPoisonTrackerUnk = DAT_GameCore::instance.cowPoisonTrackerUnk + damage * 10; + DAT_BuildingsState::instance.buildings[buildingID].currentHealth = newHealth; + switch (buildingType) { + case 0x2d: + case 0x2e: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + DAT_GameState::instance.playerDataArray[DAT_BuildingsState::instance.buildings[buildingID].owner].defensesDamagedByPlayer = (short)playerID; + } + if (unitID != 0) { + if (DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner] == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + = DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + 1; + } else { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk = 0; + } + } + if (newHealth > 0) { + continue; + } + + if (buildingType != 0x4f && (buildingType < 0x56 || buildingType > 0x59)) { + short owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_GameSynchronyState::instance.finalResults.finalBuildingsBurned[playerID] + = DAT_GameSynchronyState::instance.finalResults.finalBuildingsBurned[playerID] + 1; + DAT_GameSynchronyState::instance.finalResults.finalBuidingsDestroyed[owner] + = DAT_GameSynchronyState::instance.finalResults.finalBuidingsDestroyed[owner] + 1; + /* a per-attacker tally inside the owner's player data, 0x20 apart */ + int* tally = (int*)((char*)&DAT_GameState::instance.playerDataArray[owner].field889_0x2be0 + playerID * 0x20); + *tally = *tally + 1; + } + switch (buildingType) { + case 0x1c: + case 0x2d: + case 0x2e: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger2BikFromPlayerToPlayer, DAT_AICState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, playerID); + break; + default: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playVictory2BikFromPlayerToPlayer, DAT_AICState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, playerID); + } + + bool destroyNormally = false; + int towerX; + int towerY; + short towerOwner; + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_OILSMELTER: + if (DAT_BuildingsState::instance.buildings[buildingID].resources[7] == 0) { + destroyNormally = true; + break; + } + { + /* a smelter with oil in it goes up, and a full one throws burning oil about */ + int oilAmount = DAT_BuildingsState::instance.buildings[buildingID].resources[7]; + uint smelterTile = DAT_BuildingsState::instance.buildings[buildingID].currentTilePositionAdjusted; + int smelterX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + int smelterOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + int smelterY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + if (oilAmount < 5) { + MACRO_CALL(OpenSHC::Map::Entities_Func::SetPlaceOnFire)(smelterOwner, smelterX * 8 + 0x10, + smelterY * 8 + 0x10, this->HeightLayer[smelterTile], 3); + } else { + MACRO_CALL(OpenSHC::Map::Entities_Func::SetPlaceOnFire)(smelterOwner, smelterX * 8 + 0x10, + smelterY * 8 + 0x10, this->HeightLayer[smelterTile], 5); + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, + DAT_EntityState::ptr)(0, smelterOwner, 0, smelterX * 8 + 0x10, smelterY * 8 + 0x10, + this->HeightLayer[smelterTile], 0, 0, 0, + OpenSHC::Map::Entities::EntityTypeInt__ET_EXPLOSION, 0); + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + smelterX, smelterY, OpenSHC::DE::SHCDE::FX_IGNITE_PITCH); + } + break; + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + { + /* a gatehouse takes its drawbridges with it */ + int bridge = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, 0); + if (bridge != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[bridge].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(bridge); + bridge = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, bridge); + if (bridge != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[bridge].buildingType] + == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(bridge); + } + } + ushort gateY = DAT_BuildingsState::instance.buildings[buildingID].y; + ushort gateX = DAT_BuildingsState::instance.buildings[buildingID].x; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[buildingID].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (short)gateX, (short)gateY, OpenSHC::DE::SHCDE::FX_TOWER_SMASH); + } + break; + case OpenSHC::Map::Buildings::BT_TUNNEL: + { + /* the tunneller inside is buried where he stands */ + uint tunneller = DAT_BuildingsState::instance.buildings[buildingID].unitRefID; + if (DAT_UnitsState::instance.units[tunneller].state.generic + != (OpenSHC::Map::Units::States::US_STAND_UPUnk + | OpenSHC::Map::Units::States::US_IDLEUnk)) { + DAT_UnitsState::instance.units[tunneller].totalSizeOfPathPlan + = DAT_UnitsState::instance.units[tunneller].currentIndexInPathPlan; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::applyTunnelDamageAlongPathPlan, + DAT_UnitsState::ptr)(tunneller); + } + DAT_UnitsState::instance.units[tunneller].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + DAT_UnitsState::instance.units[tunneller].disappearFadeAlphaCountdown = 0x20; + DAT_UnitsState::instance.units[tunneller].updateTickTracker = 0x20; + } + destroyNormally = true; + break; + default: + destroyNormally = true; + break; + case OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED: + { + int rider = DAT_BuildingsState::instance.buildings[buildingID].unitRefID; + if (rider != 0 && DAT_BuildingsState::instance.buildings[buildingID].unitRefUID == DAT_UnitsState::instance.units[rider].uid) { + DAT_UnitsState::instance.units[rider].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + DAT_UnitsState::instance.units[rider].disappearFadeAlphaCountdown = 0; + DAT_UnitsState::instance.units[rider].updateTickTracker = 0; + DAT_UnitsState::instance.units[rider].workplaceBuildingID_1 = 0; + } + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + } + break; + case OpenSHC::Map::Buildings::BT_TOWER1: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x19); + towerX = DAT_BuildingsState::instance.buildings[buildingID].x; + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)(towerOwner, + (short)towerX, (short)towerY, OpenSHC::Commands::M_MAPPER_TOWER1_DESTROYED, 3, 0xf); + break; + case OpenSHC::Map::Buildings::BT_TOWER2: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerX = DAT_BuildingsState::instance.buildings[buildingID].x; + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)(towerOwner, + (short)towerX, (short)towerY, OpenSHC::Commands::M_MAPPER_TOWER2_DESTROYED, 4, 0xf); + break; + case OpenSHC::Map::Buildings::BT_TOWER3: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerX = DAT_BuildingsState::instance.buildings[buildingID].x; + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)(towerOwner, + (short)towerX, (short)towerY, OpenSHC::Commands::M_MAPPER_TOWER3_DESTROYED, 5, 0xf); + break; + case OpenSHC::Map::Buildings::BT_TOWER4: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerX = DAT_BuildingsState::instance.buildings[buildingID].x; + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)(towerOwner, + (short)towerX, (short)towerY, OpenSHC::Commands::M_MAPPER_TOWER4_DESTROYED, 6, 0xf); + break; + case OpenSHC::Map::Buildings::BT_TOWER5: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerX = DAT_BuildingsState::instance.buildings[buildingID].x; + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)(towerOwner, + (short)towerX, (short)towerY, OpenSHC::Commands::M_MAPPER_TOWER5_DESTROYED, 6, 0xf); + break; + } + + if (destroyNormally) { + int destroyedType = (short)DAT_BuildingsState::instance.buildings[buildingID].buildingType; + short destroyedOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[destroyedType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, OpenSHC::DE::SHCDE::FX_BUILDING_SMASH); + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.mapAndTime.playerTeams[destroyedOwner] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + && DAT_GameCore::instance.genieVoiceActive != FALSE) { + if (destroyedType == 0x13 || destroyedType == 0xb) { + /* "Excellent" */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playWAVSFX, DAT_SFXState::ptr)("Genie_23.wav"); + } + if (destroyedType == 8 || destroyedType == 9) { + /* "Bravo" */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playWAVSFX, DAT_SFXState::ptr)("Genie_24.wav"); + } + } + } + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(9, x, baseY); + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index cd83632a6..4fa00210c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -45435,7 +45435,7 @@ SHC_3BB0A8C1_0x00517789 | 0.0% | Pending SHC_3BB0A8C1_0x0051778A | 0.0% | Pending -SHC_3BB0A8C1_0x00517790 | 0.0% | Pending +SHC_3BB0A8C1_0x00517790 | 42.5% | 42.52% shared destroy body as SHC_3BB0A8C1_0x00518068 | 0.0% | Pending From 5c876c60ee251133332578a4d538e585c8b4f3ce Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:14:58 +0200 Subject: [PATCH 198/252] reimplement: SHC_3BB0A8C1_0x00516B80 46.04% 47.86% four labels as flags --- .../TileMapState/processDamageToBuilding.cpp | 474 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/processDamageToBuilding.cpp diff --git a/src/OpenSHC/Map/TileMapState/processDamageToBuilding.cpp b/src/OpenSHC/Map/TileMapState/processDamageToBuilding.cpp new file mode 100644 index 000000000..800a0cfb8 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/processDamageToBuilding.cpp @@ -0,0 +1,474 @@ + +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Audio/MSS/SoundSystem.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Entities.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Version.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AICState.hpp" +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_SoundSystemState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_CRENEL; + using OpenSHC::Map::LogicHelpers::L_CRENEL_VARIATIONUnk; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_UNKNOWN_WALL_RELATED; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::DE::SHCDE::eSFX; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Buildings::BuildingLogicalState; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Entities::EntityType; + using OpenSHC::Map::Units::States::UnitState; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + beware the renames! this is for both stones as well as units hitting walls decompilerscript: committed: + 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00516B80 + BOOLEnum TileMapState::processDamageToBuilding(int tile, uint xPosition, uint yPosition, int damageUnk, + int param_5, int playerID, BOOLEnum aiBuildDelayRelated, int unitID) + { + BOOLEnum destroyed = FALSE; + byte replaced = 0; + /* a negative player id is a request to spare that player's own team */ + bool spareOwnTeam = false; + if (playerID < 0) { + playerID = -playerID; + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + spareOwnTeam = true; + } + } + + uint logic = this->LogicLayer[tile]; + if ((logic & (L_BUILDING | L_KEEP_NON_MANOR_HOUSE)) == 0 && this->BuildingLayer[tile] == 0) { + if ((logic & L_WALL_OR_GATEHOUSE) == 0) { + destroyed = TRUE; + } else { + if ((logic & L_STOCKPILEUnk) != 0) { + return FALSE; + } + uint wallOwner = this->WallOwnerLayer[tile] & 7; + if (spareOwnTeam && DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[wallOwner + 1]) { + return FALSE; + } + DAT_GameState::instance.playerDataArray[wallOwner + 1].defensesDamagedByPlayer = (short)playerID; + if (unitID != 0) { + if (DAT_GameState::instance.mapAndTime.playerTeams[wallOwner + 1] == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + = DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + 1; + } else { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk = 0; + } + } + /* a wall standing alone takes half again the damage, a well connected one half */ + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countLogicPropertyInSurroundingTiles, this)( + tile, yPosition, L_KEEP_NON_MANOR_HOUSE | L_WALL_OR_GATEHOUSE); + if (this->DAT_CardinalTilesAroundTile < 2) { + damageUnk = damageUnk + damageUnk / 2; + } else if (this->DAT_CardinalTilesAroundTile > 2) { + damageUnk = damageUnk / 2; + } + if (param_5 != 0) { + damageUnk = 0; + } + DAT_TroopValueState::instance.attackInfo.field128059_0x469e0 + = DAT_TroopValueState::instance.attackInfo.field128059_0x469e0 + 1; + DAT_GameCore::instance.cowPoisonTrackerUnk + = DAT_GameCore::instance.cowPoisonTrackerUnk + damageUnk * 10; + if (param_5 == 0 && (this->LogicLayer[tile] & L_UNKNOWN_WALL_RELATED) == 0 + && this->DamageLayer[tile] == 0 + && this->DefaultHeightLayer[tile] + 60 < (uint)this->HeightLayer[tile]) { + this->HeightLayer[tile] = this->HeightLayer[tile] - 20; + } + for (int hit = 0; hit < damageUnk; hit++) { + if (this->HeightLayer[tile] <= this->DefaultHeightLayer[tile]) { + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::destroyEntitiesOnTile, + DAT_EntityState::ptr)(tile); + this->LogicLayer[tile] = this->LogicLayer[tile] + & ~(L_WALL_OR_GATEHOUSE | L_CRENEL | L_STAIRS | L_UNKNOWN_WALL_RELATED + | L_CRENEL_VARIATIONUnk); + this->HeightLayer[tile] = this->DefaultHeightLayer[tile]; + this->DamageLayer[tile] = 0; + DAT_PathFindingState::instance.toggleUpdateSeparateAreaTileMap = 1; + this->field204_0x554a30 = 1; + destroyed = TRUE; + break; + } + this->HeightLayer[tile] = this->HeightLayer[tile] - 1; + if ((char)this->DamageLayer[tile] < 200) { + this->DamageLayer[tile] = this->DamageLayer[tile] + 1; + } + } + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::updatePathLinkagesInAllEightDirections, + DAT_PathFindingState::ptr)(yPosition, tile); + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(7, xPosition, yPosition); + return ~-(uint)replaced & destroyed; + } + + int buildingID = this->BuildingLayer[tile]; + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == (BuildingLogicalState)0 || DAT_BuildingsState::instance.buildings[buildingID].logicalState == OpenSHC::Map::Buildings::BLS_REMOVE) { + return TRUE; + } + short health = DAT_BuildingsState::instance.buildings[buildingID].currentHealth; + if (health == 0) { + return TRUE; + } + DAT_GameCore::instance.cowPoisonTrackerUnk = DAT_GameCore::instance.cowPoisonTrackerUnk + damageUnk * 10; + if (DAT_BuildingDefinedData::instance.BuildingTypeHasHealth[(short)DAT_BuildingsState::instance.buildings[buildingID].buildingType] == 0) { + return TRUE; + } + if ((this->LogicLayer[tile] & 0xf000000) != 0) { + return TRUE; + } + if (spareOwnTeam && DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner]) { + return FALSE; + } + DAT_BuildingsState::instance.buildings[buildingID].currentHealth = health - (short)damageUnk; + + if (aiBuildDelayRelated == TRUE + && (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL)) { + /* a damaged gatehouse loses its drawbridges straight away */ + int bridge = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, 0); + if (bridge != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[bridge].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(bridge); + int second = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, bridge); + if (second != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[second].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(second); + } + } + } + + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + DAT_GameState::instance.playerDataArray[DAT_BuildingsState::instance.buildings[buildingID].owner].defensesDamagedByPlayer = (short)playerID; + break; + default: + break; + } + if (unitID != 0) { + if (DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner] == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + = DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk + 1; + } else { + DAT_UnitsState::instance.units[unitID].friendlyFireCounterUnk = 0; + } + } + + short remaining = DAT_BuildingsState::instance.buildings[buildingID].currentHealth; + if (remaining > 0) { + /* a siege tower's rider takes the damage with it */ + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED && DAT_BuildingsState::instance.buildings[buildingID].unitRefID != 0 + && DAT_BuildingsState::instance.buildings[buildingID].unitRefUID == DAT_UnitsState::instance.units[DAT_BuildingsState::instance.buildings[buildingID].unitRefID].uid && DAT_BuildingsState::instance.buildings[buildingID].maxHealth != 0) { + DAT_UnitsState::instance.units[DAT_BuildingsState::instance.buildings[buildingID].unitRefID].health + = ((int)remaining * DAT_UnitsState::instance.units[DAT_BuildingsState::instance.buildings[buildingID].unitRefID].maxHealth) / (int)DAT_BuildingsState::instance.buildings[buildingID].maxHealth; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(7, xPosition, yPosition); + return ~-(uint)replaced & destroyed; + } + + if (DAT_BuildingsState::instance.buildings[buildingID].owner == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL(OpenSHC::Map::Version_Func::UpdateDestroyedBuildingCountData)(1); + } + int owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + if (aiBuildDelayRelated == TRUE && DAT_GameState::instance.playerDataArray[owner].resourceRebuildDelay == 0) { + DAT_GameState::instance.playerDataArray[owner].resourceRebuildDelay = 1; + } + int destroyedType = (short)DAT_BuildingsState::instance.buildings[buildingID].buildingType; + if (destroyedType != OpenSHC::Map::Buildings::BT_UNKNOWN3 && (destroyedType < 0x56 || destroyedType > 0x59)) { + DAT_GameSynchronyState::instance.finalResults.finalBuildingsBurned[playerID] + = DAT_GameSynchronyState::instance.finalResults.finalBuildingsBurned[playerID] + 1; + DAT_GameSynchronyState::instance.finalResults.finalBuildingsDestroyedWeighted[playerID] + = DAT_GameSynchronyState::instance.finalResults.finalBuildingsDestroyedWeighted[playerID] + + DAT_BuildingDefinedData::instance.field42_0x4154[destroyedType]; + DAT_GameSynchronyState::instance.finalResults.finalBuidingsDestroyed[owner] + = DAT_GameSynchronyState::instance.finalResults.finalBuidingsDestroyed[owner] + 1; + /* a per-attacker tally inside the owner's player data, 0x20 apart */ + int* tally = (int*)((char*)&DAT_GameState::instance.playerDataArray[owner].field889_0x2be0 + playerID * 0x20); + *tally = *tally + 1; + } + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_OILSMELTER: + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + case OpenSHC::Map::Buildings::BT_TOWER1: + case OpenSHC::Map::Buildings::BT_TOWER2: + case OpenSHC::Map::Buildings::BT_TOWER3: + case OpenSHC::Map::Buildings::BT_TOWER4: + case OpenSHC::Map::Buildings::BT_TOWER5: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger2BikFromPlayerToPlayer, DAT_AICState::ptr)( + owner, playerID); + break; + default: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playVictory2BikFromPlayerToPlayer, DAT_AICState::ptr)( + owner, playerID); + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.mapAndTime.playerTeams[owner] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + && (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_TOWER4 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_TOWER5 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_CHURCH + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_CATHEDRAL) + && MACRO_CALL_MEMBER(OpenSHC::Audio::MSS::SoundSystem_Func::shouldSoundXNotBePlaying, + DAT_SoundSystemState::ptr)() + == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + if (DAT_GameCore::instance.genieVoiceActive != FALSE) { + /* "Watch it crumble" */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playWAVSFX, DAT_SFXState::ptr)("Genie_36.wav"); + } + } + + bool destroyNormally = false; + int towerX = 0; + int towerY = 0; + int towerOwner = 0; + int towerSize = 0; + MappersEnum towerCommand = OpenSHC::Commands::M_MAPPER_NULL; + switch (DAT_BuildingsState::instance.buildings[buildingID].buildingType) { + case OpenSHC::Map::Buildings::BT_OILSMELTER: + if (DAT_BuildingsState::instance.buildings[buildingID].resources[7] == 0) { + destroyNormally = true; + break; + } + { + /* a smelter with oil in it goes up, and a full one throws burning oil about */ + int oilAmount = DAT_BuildingsState::instance.buildings[buildingID].resources[7]; + int smelterX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + int smelterOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + uint smelterTile = DAT_BuildingsState::instance.buildings[buildingID].currentTilePositionAdjusted; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + int smelterY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + if (oilAmount < 5) { + MACRO_CALL(OpenSHC::Map::Entities_Func::SetPlaceOnFire)(smelterOwner, smelterX * 8 + 0x10, + smelterY * 8 + 0x10, this->HeightLayer[smelterTile], 3); + } else { + MACRO_CALL(OpenSHC::Map::Entities_Func::SetPlaceOnFire)(smelterOwner, smelterX * 8 + 0x10, + smelterY * 8 + 0x10, this->HeightLayer[smelterTile], 5); + MACRO_CALL_MEMBER(OpenSHC::Map::Entities::EntityState_Func::spawnProjectileEntity, + DAT_EntityState::ptr)(0, smelterOwner, 0, smelterX * 8 + 0x10, smelterY * 8 + 0x10, + this->HeightLayer[smelterTile], 0, 0, 0, + OpenSHC::Map::Entities::EntityTypeInt__ET_EXPLOSION, 0); + } + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + smelterX, smelterY, OpenSHC::DE::SHCDE::FX_IGNITE_PITCH); + destroyed = TRUE; + } + break; + case OpenSHC::Map::Buildings::BT_GATEHOUSELARGE: + case OpenSHC::Map::Buildings::BT_GATEHOUSESMALL: + { + int bridge = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, 0); + if (bridge != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[bridge].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(bridge); + int second = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findParticularBuilding, DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight, OpenSHC::Map::Buildings::BT_DRAWBRIDGE, bridge); + if (second != 0) { + this->showNoRubbleWhenDestroyingBuilding + = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[second].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(second); + } + } + ushort gateY = DAT_BuildingsState::instance.buildings[buildingID].y; + ushort gateX = DAT_BuildingsState::instance.buildings[buildingID].x; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)(buildingID, 50); + this->showNoRubbleWhenDestroyingBuilding = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[(short)DAT_BuildingsState::instance.buildings[buildingID].buildingType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (short)gateX, (short)gateY, OpenSHC::DE::SHCDE::FX_TOWER_SMASH); + destroyed = TRUE; + } + break; + case OpenSHC::Map::Buildings::BT_TUNNEL: + { + /* the tunneller inside is buried where he stands */ + uint tunneller = DAT_BuildingsState::instance.buildings[buildingID].unitRefID; + if (DAT_UnitsState::instance.units[tunneller].state.generic + != (OpenSHC::Map::Units::States::US_STAND_UPUnk + | OpenSHC::Map::Units::States::US_IDLEUnk)) { + DAT_UnitsState::instance.units[tunneller].totalSizeOfPathPlan = DAT_UnitsState::instance.units[tunneller].currentIndexInPathPlan; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::applyTunnelDamageAlongPathPlan, + DAT_UnitsState::ptr)(tunneller); + } + DAT_UnitsState::instance.units[tunneller].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + DAT_UnitsState::instance.units[tunneller].disappearFadeAlphaCountdown = 0x20; + DAT_UnitsState::instance.units[tunneller].updateTickTracker = 0x20; + } + destroyNormally = true; + break; + default: + destroyNormally = true; + break; + case OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED: + { + int rider = DAT_BuildingsState::instance.buildings[buildingID].unitRefID; + if (rider != 0 && DAT_BuildingsState::instance.buildings[buildingID].unitRefUID == DAT_UnitsState::instance.units[rider].uid) { + DAT_UnitsState::instance.units[rider].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + DAT_UnitsState::instance.units[rider].disappearFadeAlphaCountdown = 0; + DAT_UnitsState::instance.units[rider].updateTickTracker = 0; + DAT_UnitsState::instance.units[rider].workplaceBuildingID_1 = 0; + } + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + destroyed = TRUE; + } + break; + case OpenSHC::Map::Buildings::BT_TOWER1: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x19); + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + towerX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + towerSize = 3; + towerCommand = OpenSHC::Commands::M_MAPPER_TOWER1_DESTROYED; + replaced = 1; + break; + case OpenSHC::Map::Buildings::BT_TOWER2: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + towerX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + towerSize = 4; + towerCommand = OpenSHC::Commands::M_MAPPER_TOWER2_DESTROYED; + replaced = 1; + break; + case OpenSHC::Map::Buildings::BT_TOWER3: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + towerX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + towerSize = 5; + towerCommand = OpenSHC::Commands::M_MAPPER_TOWER3_DESTROYED; + replaced = 1; + break; + case OpenSHC::Map::Buildings::BT_TOWER4: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + towerX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + towerSize = 6; + towerCommand = OpenSHC::Commands::M_MAPPER_TOWER4_DESTROYED; + replaced = 1; + break; + case OpenSHC::Map::Buildings::BT_TOWER5: + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processDamageToUnitsOnBuilding, DAT_BuildingsState::ptr)( + buildingID, 0x32); + towerOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + towerX = (short)DAT_BuildingsState::instance.buildings[buildingID].x; + DAT_BuildingsState::instance.buildings[buildingID].noRubble = 0; + towerY = (short)DAT_BuildingsState::instance.buildings[buildingID].y; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::deleteBuilding, DAT_BuildingsState::ptr)(buildingID); + towerSize = 6; + towerCommand = OpenSHC::Commands::M_MAPPER_TOWER5_DESTROYED; + replaced = 1; + break; + } + + if (replaced != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, this)( + towerOwner, towerX, towerY, towerCommand, towerSize, 0xf); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + towerX, towerY, OpenSHC::DE::SHCDE::FX_TOWER_SMASH); + destroyed = TRUE; + } else if (destroyNormally) { + short rubbleOwner = DAT_BuildingsState::instance.buildings[buildingID].owner; + this->showNoRubbleWhenDestroyingBuilding = DAT_BuildingDefinedData::instance.BuildingShowRubbleWhenDestroyed[destroyedType] == 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + (short)DAT_BuildingsState::instance.buildings[buildingID].x, (short)DAT_BuildingsState::instance.buildings[buildingID].y, OpenSHC::DE::SHCDE::FX_BUILDING_SMASH); + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY + && playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID + && DAT_GameState::instance.mapAndTime.playerTeams[rubbleOwner] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + && DAT_GameCore::instance.genieVoiceActive != FALSE) { + if (destroyedType == 0x13 || destroyedType == 0xb) { + /* "Excellent" */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playWAVSFX, DAT_SFXState::ptr)("Genie_23.wav"); + } + if (destroyedType == 8 || destroyedType == 9) { + /* "Bravo" */ + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playWAVSFX, DAT_SFXState::ptr)("Genie_24.wav"); + } + } + destroyed = TRUE; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkAndPathLayer, + DAT_PathFindingState::ptr)(7, xPosition, yPosition); + return ~-(uint)replaced & destroyed; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4fa00210c..46e464e05 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -45133,7 +45133,7 @@ SHC_3BB0A8C1_0x00516B73 | 0.0% | Pending SHC_3BB0A8C1_0x00516B74 | 0.0% | Pending -SHC_3BB0A8C1_0x00516B80 | 0.0% | Pending +SHC_3BB0A8C1_0x00516B80 | 46.0% | 47.86% four labels as flags SHC_3BB0A8C1_0x005176C8 | 0.0% | Pending From 0dff5e723e8b7892795eaa020b406f8585f00061 Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:18:11 +0200 Subject: [PATCH 199/252] reimplement: SHC_3BB0A8C1_0x005037B0 36.36% 36.36% repaired from unbuildab --- .../checkBuildingCanBePlacedHere.cpp | 903 ++++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 904 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/checkBuildingCanBePlacedHere.cpp diff --git a/src/OpenSHC/Map/TileMapState/checkBuildingCanBePlacedHere.cpp b/src/OpenSHC/Map/TileMapState/checkBuildingCanBePlacedHere.cpp new file mode 100644 index 000000000..c7e5869f9 --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/checkBuildingCanBePlacedHere.cpp @@ -0,0 +1,903 @@ + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingFailReasonEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Commands::MappersEnum; + using OpenSHC::Game::GameMode; + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingFailReasonEnum; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Unable to use type for symbol _x + */ + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x005037B0 + void TileMapState::checkBuildingCanBePlacedHere( + int playerID, uint x, uint y__fertileLandCount, MappersEnum commandBuildingType, int buildingSize) + { + uint uVar1; + byte bVar2; + BuildingType _buildingType; + int _buildRange; + BOOLEnum BVar3; + int iVar4; + uint uVar5; + int iVar6; + int iVar7; + MappersEnum _commandBuildingType; + int iVar8; + int* piVar9; + bool bVar10; + bool bVar11; + int _grassCount; + int _distance; + int _range; + int _boulderCount; + int _ironCount; + int _oilCount; + int local_4; + uint _x; + uint _y; + /* the parameter carries the y position in, then is reused as a tile counter */ + _y = y__fertileLandCount; + _x = x; + bVar11 = buildingSize < 0; + local_4 = 0; + if (bVar11) { + buildingSize = 2; + } + _commandBuildingType = (MappersEnum)(short)(undefined2)commandBuildingType; + this->buildingPlacementFail = FALSE; + this->placementWarning = 0; + this->field127_0x554944 = 0; + this->uiBuildingRotation = 0xf; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingSpriteSheetID_1 + = DAT_BuildingDefinedData::instance.Building_SpriteSheet_ID_Array_1[_buildingType].intValue; + this->buildingSpriteID1 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getSpriteID, DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingSpriteID2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getSpriteID2, DAT_BuildingsState::ptr)(_commandBuildingType); + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingHeightLimit = DAT_BuildingDefinedData::instance.BuildingPlacement_HeightLimit[_buildingType]; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingMaxHeightDifference + = DAT_BuildingDefinedData::instance.BuildingPlacement_MaxHeightDifference[_buildingType]; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingPlacementProperty_3 + = DAT_BuildingDefinedData::instance.BuildingPlacement_Property_3[_buildingType]; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingPlacementProperty_4 + = DAT_BuildingDefinedData::instance.BuildingPlacement_Property_4[_buildingType]; + if (((DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) + || (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) + || (DAT_GameSynchronyState::instance.currentAIArray[playerID] == 0)) { + this->buildingPlacementProperty_4 = 0; + } + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingPlacementProperty_5 + = DAT_BuildingDefinedData::instance.BuildingPlacement_Property_5[_buildingType]; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingPlacementProperty_6 + = DAT_BuildingDefinedData::instance.BuildingPlacement_Property_6[_buildingType]; + _buildingType + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::convertCommandBuildingTypeToBuildingType, + DAT_BuildingsState::ptr)(_commandBuildingType); + this->buildingPlacementProperty_7 + = DAT_BuildingDefinedData::instance.BuildingPlacement_Property_7[_buildingType]; + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_SIEGE_TOWER_BASE) { + return; + } + _boulderCount = 0; + _ironCount = 0; + _oilCount = 0; + y__fertileLandCount = 0; + _grassCount = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::storeMinAndMaxHeightOfArea, this)(x, _y, buildingSize); + if (bVar11) + goto switchD_0050397c_caseD_33; + if (0x138 < (int)_commandBuildingType) { + if (325 < (int)_commandBuildingType) { + if ((int)_commandBuildingType < 328) + goto switchD_0050397c_caseD_33; + if (_commandBuildingType == 358) + goto switchD_0050397c_caseD_be; + } + switchD_0050397c_caseD_35: + if ((DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR) + && (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT)) { + bVar10 = DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY; + bVar11 = true; + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + x, buildingSize); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, this->buildingX + _x, this->buildingY + _y, + (int)((int)((-(uint)bVar10 & 0xfffffff1) + 0x1e))); + if (BVar3 != FALSE) { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x11); + bVar11 = false; + break; + } + x = x + 1; + } while ((int)x < this->constructionTileCount); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isSignPostWithinDistance, + DAT_PathFindingState::ptr)(_x, _y, DAT_GameState::instance.mapAndTime.unk_signpostDistance + 5); + if (BVar3 == FALSE) { + if (bVar11) + goto LAB_00503d46; + } else { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x15); + } + LAB_00503d3c: + this->buildingPlacementFail = TRUE; + } + goto LAB_00503d46; + } + if (_commandBuildingType == OpenSHC::Commands::M_MAPPER_DOG_CAGE) { + if (9 < DAT_GameState::instance.playerDataArray[playerID].dogCageCount) { + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)1000); + return; + } + switchD_0050397c_caseD_62: + local_4 = 5; + switchD_0050397c_caseD_64: + if (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_EDITOR) { + iVar8 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar8, buildingSize); + iVar4 + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, + DAT_PathFindingState::ptr)(playerID, (int)((int)(this->buildingX + x)), + (int)((int)(this->buildingY + _y)), 7, -1, -1, -1); + if (iVar4 != 0) + goto LAB_005039d6; + iVar8 = iVar8 + 1; + } while (iVar8 < this->constructionTileCount); + } else if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT) { + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) { + _distance = 30; + _range = 30; + } else { + MACRO_CALL_MEMBER( + OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, DAT_GameSynchronyState::ptr)(playerID); + _distance = 15; + _range = 7; + } + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + x, buildingSize); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, this->buildingX + _x, this->buildingY + _y, _distance); + if (BVar3 != FALSE) { + LAB_00503b32: + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x11); + LAB_00503b48: + bVar11 = false; + break; + } + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + iVar8 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::isOpponentBuildingInRange, + DAT_PathFindingState::ptr)(playerID, (int)((int)(this->buildingX + _x)), + (int)((int)(this->buildingY + _y)), _range, -1, -1, -1); + if (iVar8 != 0) + goto LAB_00503b32; + _buildRange + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getCastleBuildRangeForMapSize, this)(); + iVar8 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::isTileInRangeOfKeepRange, + DAT_PathFindingState::ptr)( + playerID, this->buildingX + _x, this->buildingY + _y, _buildRange + local_4); + if (iVar8 == 0) + goto LAB_00503b11; + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x12); + goto LAB_00503b48; + } + LAB_00503b11: + x = x + 1; + bVar11 = true; + } while ((int)x < this->constructionTileCount); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isSignPostWithinDistance, + DAT_PathFindingState::ptr)(_x, _y, DAT_GameState::instance.mapAndTime.unk_signpostDistance + 5); + if (BVar3 == FALSE) { + if (bVar11) + goto LAB_00503d46; + } else { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x15); + } + this->buildingPlacementFail = TRUE; + if (this->buildingPlacementFailReason == OpenSHC::Map::Buildings::BFRE_DEFAULT_CANT_PLACE_THAT_THERE) { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x12); + } + } + } else { + switch (_commandBuildingType) { + case OpenSHC::Commands::M_MAPPER_WOODSMAN: + case OpenSHC::Commands::M_MAPPER_OXENBASE: + case OpenSHC::Commands::M_MAPPER_QUARRY: + case OpenSHC::Commands::M_MAPPER_TUNNEL: + case OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION: + case OpenSHC::Commands::M_MAPPER_WHEATFARM: + case OpenSHC::Commands::M_MAPPER_HOPSFARM: + case OpenSHC::Commands::M_MAPPER_APPLEFARM: + case OpenSHC::Commands::M_MAPPER_CATTLEFARM: + case OpenSHC::Commands::M_MAPPER_IRON_MINE: + case OpenSHC::Commands::M_MAPPER_PITCH_WORKINGS: + case OpenSHC::Commands::M_MAPPER_QUARRYPILE: + goto switchD_0050397c_caseD_33; + case OpenSHC::Commands::M_MAPPER_STORES: + case OpenSHC::Commands::M_MAPPER_GRANARY: + case OpenSHC::Commands::M_MAPPER_ARMOURY: + if (DAT_GameSynchronyState::instance.currentGameMode != OpenSHC::Game::GM_SOLITARY) { + iVar8 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar8, buildingSize); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, this->buildingX + x, this->buildingY + _y, 3); + if (BVar3 != FALSE) + goto LAB_005039d6; + iVar8 = iVar8 + 1; + } while (iVar8 < this->constructionTileCount); + } + break; + default: + goto switchD_0050397c_caseD_35; + case OpenSHC::Commands::M_MAPPER_KILLING_PIT: + case OpenSHC::Commands::M_MAPPER_PITCH_DITCH: + case OpenSHC::Commands::M_MAPPER_DRAWBRIDGE: + goto switchD_0050397c_caseD_62; + case OpenSHC::Commands::M_MAPPER_GATEHOUSE: + case OpenSHC::Commands::M_MAPPER_GATE_MAIN: + case OpenSHC::Commands::M_MAPPER_GATE_INNER: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD: + case OpenSHC::Commands::M_MAPPER_GATE_POSTERN: + case OpenSHC::Commands::M_MAPPER_MOAT: + case OpenSHC::Commands::M_MAPPER_ANTIMOAT: + case OpenSHC::Commands::M_MAPPER_TOWER1: + case OpenSHC::Commands::M_MAPPER_TOWER2: + case OpenSHC::Commands::M_MAPPER_TOWER3: + case OpenSHC::Commands::M_MAPPER_TOWER4: + case OpenSHC::Commands::M_MAPPER_TOWER5: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1A: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1B: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1C: + case OpenSHC::Commands::M_MAPPER_GATE_WOOD1D: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE1B: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2A: + case OpenSHC::Commands::M_MAPPER_GATE_STONE2B: + goto switchD_0050397c_caseD_64; + case OpenSHC::Commands::M_MAPPER_CATAPULT: + case OpenSHC::Commands::M_MAPPER_TREBUCHET: + case OpenSHC::Commands::M_MAPPER_SIEGE_TOWER: + case OpenSHC::Commands::M_MAPPER_BATTERING_RAM: + case OpenSHC::Commands::M_MAPPER_PORTABLE_SHIELD: + switchD_0050397c_caseD_be: + if ((DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_EDITOR) + && (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SIEGE_THAT)) { + iVar8 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar8, buildingSize); + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::isEnemyTooCloseUnk, + DAT_PathFindingState::ptr)(playerID, this->buildingX + x, this->buildingY + _y, 3); + if (BVar3 != FALSE) + goto LAB_005039d6; + iVar8 = iVar8 + 1; + } while (iVar8 < this->constructionTileCount); + } + } + } + LAB_00503d46: + if (this->buildingPlacementFail == FALSE) { + iVar8 = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + iVar8, buildingSize); + iVar4 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findSomeSuitableLocationUnk, + DAT_PathFindingState::ptr)(playerID, this->buildingX + _x, this->buildingY + _y, 2); + if (iVar4 != 0) { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x11); + this->buildingPlacementFail = TRUE; + break; + } + iVar8 = iVar8 + 1; + } while (iVar8 < this->constructionTileCount); + } + switchD_0050397c_caseD_33: + if (((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_DRAWBRIDGE) && (0xc < this->buildingMaxHeight)) { + this->buildingPlacementFail = TRUE; + } + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, buildingSize); + uVar5 = this->buildingY + _y; + if (399 < this->buildingX + _x) { + this->buildingPlacementFail = 2; + return; + } + if (399 < uVar5) { + this->buildingPlacementFail = 2; + return; + } + if (*(char*)(uVar5 * 400 + 0x21aec98 + this->buildingX + _x) == '\0') { + this->buildingPlacementFail = 2; + return; + } + iVar8 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + this->buildingX + _x; + uVar5 = this->LogicLayer[iVar8]; + if ((uVar5 & 0x30) != 0) { + this->buildingPlacementFail = 2; + return; + } + if ((uVar5 & 0x20000) != 0) { + _boulderCount = _boulderCount + 1; + } + if ((uVar5 & 0x80000) != 0) { + _ironCount = _ironCount + 1; + } + if ((int)uVar5 < 0) { + _oilCount = _oilCount + 1; + } + if ((uVar5 & 0x100000) == 0) { + bVar2 = this->Logic2Layer[iVar8]; + if ((bVar2 & 0x10) != 0) { + /* + grass + */ + y__fertileLandCount = y__fertileLandCount + 1; + _grassCount = _grassCount + 1; + } + if ((char)bVar2 < '\0') { + /* + thick scrub + */ + y__fertileLandCount = y__fertileLandCount + 1; + _grassCount = _grassCount + 1; + } + if ((bVar2 & 1) != 0) { + /* + scrub + */ + y__fertileLandCount = y__fertileLandCount + 1; + } + } + iVar8 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar8, playerID, _commandBuildingType, 0); + if (iVar8 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + } while ((int)x < this->constructionTileCount); + if (((((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_CATTLEFARM) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_WHEATFARM)) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_HOPSFARM)) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_APPLEFARM)) { + if ((int)y__fertileLandCount < this->constructionTileCount) { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x16); + this->buildingPlacementFail = TRUE; + return; + } + if (_grassCount < 50) { + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x17); + this->buildingPlacementFail = TRUE; + } + } else { + if ((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_QUARRY) { + if ((((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_KEEP1) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_KEEP2)) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_KEEP3)) { + buildingSize = (_commandBuildingType - OpenSHC::Commands::M_MAPPER_KEEP1) * 0x60 + 0xb491b8; + commandBuildingType = OpenSHC::Commands::M_MAPPER_NULL; + do { + uVar5 = *(int*)(buildingSize + 4) + _y; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(*(int*)buildingSize + _x, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar8 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + + *(int*)buildingSize + _x; + if ((this->LogicLayer[iVar8] & 0x30) != 0) { + this->buildingPlacementFail = 2; + return; + } + iVar8 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar8, playerID, _commandBuildingType, 0); + if (iVar8 != 0) { + this->buildingPlacementFail = TRUE; + } + buildingSize = buildingSize + 8; + commandBuildingType = (MappersEnum)(commandBuildingType + OpenSHC::Commands::M_MAPPER_AREA); + } while ((int)commandBuildingType < 3); + iVar4 = (_commandBuildingType - OpenSHC::Commands::M_MAPPER_KEEP1) * 0x20; + iVar6 = _x + *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 900); + iVar8 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 904); + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 7); + uVar5 = this->buildingY + _y + iVar8; + uVar1 = this->buildingX + iVar6; + if (399 < uVar1) { + this->buildingPlacementFail = 2; + return; + } + if (399 < uVar5) { + this->buildingPlacementFail = 2; + return; + } + if (*(char*)(uVar5 * 400 + 0x21aec98 + uVar1) == '\0') { + this->buildingPlacementFail = 2; + return; + } + iVar7 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + this->buildingX + + iVar6; + if ((this->LogicLayer[iVar7] & 0x30) != 0) { + this->buildingPlacementFail = 2; + return; + } + iVar7 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar7, playerID, _commandBuildingType, 0); + if (iVar7 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + } while ((int)x < this->constructionTileCount); + iVar8 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 1000); + iVar4 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar4 + 0x3e4) + _x; + x = 0; + while (true) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 5); + iVar6 = this->buildingX; + uVar5 = this->buildingY + iVar8 + _y; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(iVar4 + this->buildingX, uVar5); + if ((BVar3 == FALSE) + || (iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + iVar6 + + iVar4, + (this->LogicLayer[iVar6] & 0x30) != 0)) + break; + iVar6 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + return; + } + } + } else { + if (((((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_GATE_WOOD1A) + && ((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_GATE_WOOD1B)) + && ((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_GATE_WOOD1C)) + && ((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_GATE_WOOD1D)) { + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_IRON_MINE) { + if (3 < _ironCount) { + return; + } + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_NOT_IRON_ORE; + this->buildingPlacementFail = TRUE; + return; + } + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_PITCH_WORKINGS) { + if (0 < _oilCount) { + return; + } + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_NOT_OIL_MARSH; + this->buildingPlacementFail = TRUE; + return; + } + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_STORES) { + if (DAT_GameState::instance.playerDataArray[playerID].stockpile.id == 0) { + return; + } + iVar8 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getEmptyBuildingCount, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_STOCKPILE); + if (iVar8 < 0x20) { + BVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::hasBuildingAsNeighbour, + DAT_BuildingsState::ptr)(playerID, (int)((int)(_x)), (int)((int)(_y)), buildingSize, + OpenSHC::Map::Buildings::BT_STOCKPILE); + if (BVar3 != FALSE) { + return; + } + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_NOT_ADJ_STOCKPILE; + return; + } + this->buildingPlacementFail = TRUE; + return; + } + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_GRANARY) { + if (DAT_GameState::instance.playerDataArray[playerID].granary.id == 0) { + return; + } + iVar8 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getEmptyBuildingCount, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_GRANARY); + if (iVar8 < 8) { + BVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::hasBuildingAsNeighbour, + DAT_BuildingsState::ptr)(playerID, (int)((int)(_x)), (int)((int)(_y)), buildingSize, + OpenSHC::Map::Buildings::BT_GRANARY); + if (BVar3 != FALSE) { + return; + } + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_NOT_ADJ_GRANARY; + return; + } + this->buildingPlacementFail = TRUE; + return; + } + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_ARMOURY) { + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + return; + } + iVar8 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getEmptyBuildingCount, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_ARMORY); + if (iVar8 < 8) { + BVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::hasBuildingAsNeighbour, + DAT_BuildingsState::ptr)(playerID, (int)((int)(_x)), (int)((int)(_y)), buildingSize, + OpenSHC::Map::Buildings::BT_ARMORY); + if (BVar3 != FALSE) { + return; + } + this->buildingPlacementFail = TRUE; + this->buildingPlacementFailReason = OpenSHC::Map::Buildings::BFRE_NOT_ADJ_ARMORY; + return; + } + this->buildingPlacementFail = TRUE; + return; + } + if (((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_BARRACKS_EURO) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_BARRACKS_ARAB)) { + iVar4 = _x + + DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][0] + .x; + iVar8 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][0] + .y; + x = 0; + while (true) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 5); + uVar5 = this->buildingY + _y + iVar8; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar4, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + + this->buildingX + iVar4; + if ((this->LogicLayer[iVar6] & 0x30) != 0) + break; + iVar6 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + iVar4 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][1] + .x + + _x; + iVar8 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][1] + .y; + x = 0; + while (true) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( + x, 5); + iVar6 = this->buildingX; + uVar5 = this->buildingY + iVar8 + _y; + BVar3 = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar4, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + + iVar6 + iVar4; + if ((this->LogicLayer[iVar6] & 0x30) != 0) + break; + iVar6 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + iVar4 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][2] + .x + + _x; + iVar8 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][2] + .y; + x = 0; + while (true) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, + this)(x, 5); + iVar6 = this->buildingX; + uVar5 = this->buildingY + iVar8 + _y; + BVar3 = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar4, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5] + .addXgetTile + + iVar6 + iVar4; + if ((this->LogicLayer[iVar6] & 0x30) != 0) + break; + iVar6 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + return; + } + } + this->buildingPlacementFail = 2; + return; + } + } + this->buildingPlacementFail = 2; + return; + } + } + this->buildingPlacementFail = 2; + return; + } + if (((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_ENGINEERS_GUILD) + || ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_TUNNELERS_GUILD)) { + iVar4 = _x + + DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][1] + .x; + iVar8 = DAT_TerrainDefinedData::instance + .BuildingPartsOffsets[this->DAT_TempBuildingRotation][1] + .y; + x = 0; + while (true) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 5); + uVar5 = this->buildingY + _y + iVar8; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar4, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + + this->buildingX + iVar4; + if ((this->LogicLayer[iVar6] & 0x30) != 0) + break; + iVar6 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + return; + } + } + this->buildingPlacementFail = 2; + return; + } + if ((undefined2)commandBuildingType == OpenSHC::Commands::M_MAPPER_OIL_SMELTER) { + iVar4 + = _x + DAT_TerrainDefinedData::instance.field63_0x19c[this->DAT_TempBuildingRotation].x; + iVar8 = DAT_TerrainDefinedData::instance.field63_0x19c[this->DAT_TempBuildingRotation].y; + x = 0; + while (true) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 4); + uVar5 = this->buildingY + _y + iVar8; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar4, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + + this->buildingX + iVar4; + if ((this->LogicLayer[iVar6] & 0x30) != 0) + break; + iVar6 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, this)( + iVar6, playerID, OpenSHC::Commands::M_MAPPER_OIL_SMELTER, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + if (this->constructionTileCount <= (int)x) { + return; + } + } + this->buildingPlacementFail = 2; + return; + } + if ((undefined2)commandBuildingType != OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION) { + return; + } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::algTunnelerFindTarget, + DAT_PathFindingState::ptr)( + playerID, 0, (int)((int)(76)), (int)((int)(_x)), (int)((int)(_y))); + if (DAT_PathFindingState::instance.ALG_TargetTile != 0) { + return; + } + this->buildingPlacementFail = TRUE; + return; + } + iVar8 = _commandBuildingType * 3 + -0x1a4; + iVar6 = _x + *(int*)((int)DAT_TerrainDefinedData::ptr + iVar8 * 8 + 0x56c); + iVar8 = iVar8 * 8; + iVar4 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar8 + 0x570); + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 3); + uVar5 = this->buildingY + _y + iVar4; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->buildingX + iVar6, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar7 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + this->buildingX + + iVar6; + if ((this->LogicLayer[iVar7] & 0x30) != 0) { + this->buildingPlacementFail = 2; + return; + } + iVar7 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar7, playerID, _commandBuildingType, 0); + if (iVar7 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + } while ((int)x < this->constructionTileCount); + iVar4 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar8 + 0x57c); + iVar8 = *(int*)((int)DAT_TerrainDefinedData::ptr + iVar8 + 0x578) + _x; + x = 0; + do { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)(x, 3); + iVar6 = this->buildingX; + uVar5 = this->buildingY + iVar4 + _y; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(iVar8 + this->buildingX, uVar5); + if (BVar3 == FALSE) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = DAT_ViewportRenderState::instance.translationMatrix[uVar5].addXgetTile + iVar6 + iVar8; + if ((this->LogicLayer[iVar6] & 0x30) != 0) { + this->buildingPlacementFail = 2; + return; + } + iVar6 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar6, playerID, _commandBuildingType, 0); + if (iVar6 != 0) { + this->buildingPlacementFail = TRUE; + } + x = x + 1; + } while ((int)x < this->constructionTileCount); + commandBuildingType = OpenSHC::Commands::M_MAPPER_NULL; + piVar9 + = (int*)((int)DAT_TerrainDefinedData::ptr + (_commandBuildingType * 3 + -0x1a4) * 0x10 + 0x5cc); + while (true) { + iVar8 = piVar9[1]; + iVar4 = *piVar9; + BVar3 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(_x + iVar4, iVar8 + _y); + if ((BVar3 == FALSE) + || (iVar8 = DAT_ViewportRenderState::instance.translationMatrix[iVar8 + _y].addXgetTile + + iVar4 + _x, + (this->LogicLayer[iVar8] & 0x30) != 0)) + break; + iVar8 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::isBuildingPlacementAllowedAtTile, + this)(iVar8, playerID, _commandBuildingType, 0); + if (iVar8 != 0) { + this->buildingPlacementFail = TRUE; + } + commandBuildingType = (MappersEnum)(commandBuildingType + OpenSHC::Commands::M_MAPPER_AREA); + piVar9 = piVar9 + 2; + if (5 < (int)commandBuildingType) { + return; + } + } + } + this->buildingPlacementFail = 2; + return; + } + if (_boulderCount < 8) { + this->buildingPlacementFail = TRUE; + return; + } + } + return; + LAB_005039d6: + this->buildingPlacementFailReason = ((BuildingFailReasonEnum)0x11); + goto LAB_00503d3c; + } + +} +} diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 46e464e05..82f62dece 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -41655,7 +41655,7 @@ SHC_3BB0A8C1_0x005034A0 | 54.5% | 57.24% regalloc SHC_3BB0A8C1_0x00503720 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x005037B0 | 0.0% | Pending +SHC_3BB0A8C1_0x005037B0 | 36.4% | 36.36% repaired from unbuildab SHC_3BB0A8C1_0x005046A0 | 0.0% | Pending From cce53a59b705b34153731e82a849fa81272a4e01 Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:25:00 +0200 Subject: [PATCH 200/252] header: make forceUpdateTextureTilemap signed updateGfxLayer gates on it with jg, not ja, so the field is an int. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NaSkbxngnm28vFqxp3wNZs --- src/OpenSHC/Map/TileMapState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/Map/TileMapState.hpp b/src/OpenSHC/Map/TileMapState.hpp index 530648c03..7900da981 100644 --- a/src/OpenSHC/Map/TileMapState.hpp +++ b/src/OpenSHC/Map/TileMapState.hpp @@ -100,7 +100,7 @@ namespace Map { int temporaryTerrainTypeArray[1000]; // 0x0055292C length: 4000 int temporaryTerrainTypeBinaryArray[1000]; // 0x005538CC length: 4000 undefined4 forceUpdateLogicalAndMiscDisplayLayers; // 0x0055486C length: 4 - undefined4 forceUpdateTextureTilemap; // 0x00554870 length: 4 + int forceUpdateTextureTilemap; // 0x00554870 length: 4 int forceUpdateGFXLayers; // 0x00554874 length: 4 int forceUpdateMacroLayerFlag; // 0x00554878 length: 4 undefined4 field68_0x55487c; // 0x0055487C length: 4 From aa8c3ee52aef7ec83e0c91656ac93056b21b613a Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 30 Sep 2026 00:25:07 +0200 Subject: [PATCH 201/252] reimplement: SHC_3BB0A8C1_0x00509180 15.65% 15.65% repaired, arms restored --- .../Map/TileMapState/updateGfxLayer.cpp | 3219 +++++++++++++++++ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 3220 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/Map/TileMapState/updateGfxLayer.cpp diff --git a/src/OpenSHC/Map/TileMapState/updateGfxLayer.cpp b/src/OpenSHC/Map/TileMapState/updateGfxLayer.cpp new file mode 100644 index 000000000..35f61e4db --- /dev/null +++ b/src/OpenSHC/Map/TileMapState/updateGfxLayer.cpp @@ -0,0 +1,3219 @@ + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Rendering/ViewportRenderState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TerrainDefinedData.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +/* the original was built without optimisation: frame pointer, locals off ebp, sub esp, 0x118 */ +#pragma optimize("", off) + +namespace OpenSHC { +namespace Map { + + using OpenSHC::Map::LogicHelpers::L_BORDER; + using OpenSHC::Map::LogicHelpers::L_BORDER_EDGE; + using OpenSHC::Map::LogicHelpers::L_BOULDERS; + using OpenSHC::Map::LogicHelpers::L_BUILDING; + using OpenSHC::Map::LogicHelpers::L_DEFAULT_EARTH_OR_TEXTURE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_APPLE; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_DAIRY; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_HOP; + using OpenSHC::Map::LogicHelpers::L_FARM_FIELD_WHEAT; + using OpenSHC::Map::LogicHelpers::L_FORD; + using OpenSHC::Map::LogicHelpers::L_IRON; + using OpenSHC::Map::LogicHelpers::L_KEEP_NON_MANOR_HOUSE; + using OpenSHC::Map::LogicHelpers::L_MARSH; + using OpenSHC::Map::LogicHelpers::L_MOAT; + using OpenSHC::Map::LogicHelpers::L_OIL; + using OpenSHC::Map::LogicHelpers::L_PEBBLES; + using OpenSHC::Map::LogicHelpers::L_PLAIN2_AND_PITCH; + using OpenSHC::Map::LogicHelpers::L_RIVER; + using OpenSHC::Map::LogicHelpers::L_ROCKY; + using OpenSHC::Map::LogicHelpers::L_SEA; + using OpenSHC::Map::LogicHelpers::L_STAIRS; + using OpenSHC::Map::LogicHelpers::L_STOCKPILEUnk; + using OpenSHC::Map::LogicHelpers::L_WALL_OR_GATEHOUSE; + + using OpenSHC::Game::GameMode2; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + WARNING: Restarted to delay deadcode elimination for space: ram + */ + /* + WARNING: Enum "MappersEnum": Some values do not have unique names + */ + /* + WARNING: Enum "DPSEND_EnumInt": Some values do not have unique names + */ + /* + WARNING: Enum "DPERRInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + // FUNCTION: STRONGHOLDCRUSADER 0x00509180 + void TileMapState::updateGfxLayer() + { + OpenSHC::Map::Buildings::BuildingTypeShort BVar1; + ushort uVar2; + ushort uVar3; + short sVar4; + short sVar5; + byte bVar6; + byte bVar7; + int sVar8; + bool bVar10; + int bVar9; + BOOLEnum BVar11; + uint uVar12; + int iVar13; + int iVar14; + uint uVar15; + byte bVar16; + int iVar17; + uint* puVar18; + byte bVar19; + int local_d4; + uint local_c0; + int local_b8; + int local_b4; + short local_b0; + int local_ac; + int local_a4; + int local_a0; + short local_9c; + int local_94; + uint local_74; + int local_70; + int local_68; + int local_60; + int local_54; + uint local_48; + short local_44; + int local_38; + int local_30; + int local_24; + int local_18; + int local_14; + int local_10; + int local_c; + int local_8; + sVar8 = 0; + if (0 < this->forceUpdateTextureTilemap) { + this->forceUpdateTextureTilemap = this->forceUpdateTextureTilemap + -1; + local_c = DAT_PathFindingState::instance.mappingYRelated % 10; + for (local_18 = this->someIndex; local_18 <= this->someLimit; local_18 = local_18 + 1) { + for (local_10 = this->someYLike; local_10 <= this->someYLikeLimit; local_10 = local_10 + 1) { + if (*(char*)(local_18 * 0x28 + 0x1f93438 + local_10) != '\0') { + local_24 = local_c; + local_c = 0; + for (; local_24 < 10; local_24 = local_24 + 1) { + this->DAT_SomeY = local_18 * 10 + local_24; + this->DAT_SomeX = local_10 * 10; + for (local_30 = 0; local_30 < 10; local_30 = local_30 + 1) { + bVar9 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, (uint)((int)(this->DAT_SomeY))); + if ((bVar9 != 0) + && (this->DAT_SomeTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY), + this->ChangedLayer[this->DAT_SomeTile] != 0)) { + if (this->BuildingLayer[this->DAT_SomeTile] == 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::computeTileLuminescence, + this)(this->DAT_SomeTile, this->DAT_SomeY); + iVar17 = this->DAT_SomeX; + this->FloatingLayer[this->DAT_SomeTile] = 0; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xfc3f; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xf7ff; + if ((this->LogicLayer[this->DAT_SomeTile] & L_RIVER) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_FORD) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_FARM_FIELD_WHEAT) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_FARM_FIELD_HOP) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_FARM_FIELD_APPLE + | L_FARM_FIELD_DAIRY) + == 0) { + if ((((this->LogicLayer[this->DAT_SomeTile] + & L_WALL_OR_GATEHOUSE + | L_BUILDING | L_KEEP_NON_MANOR_HOUSE) + == 0) + && (this->BuildingWasLayer[this->DAT_SomeTile] + != '\0')) + && ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0x10) + != 0)) { + local_44 = 0; + switch (this->BuildingWasLayer[this->DAT_SomeTile]) { + case '\t': + case '\n': + case '\v': + case '\x18': + case '\x19': + case '$': + case '%': + case '&': + case '(': + case ')': + case '*': + case '+': + case ',': + case '-': + case '.': + case '0': + case '4': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'Z': + case 'j': + local_44 = 0xc; + } + if ((this->MiscDisplayLayer[this->DAT_SomeTile] + & 0x2000) + == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed::instance[0x95] + + local_44 + 4 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed::instance[0x95] + + local_44 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } + } else if ((this->LogicLayer[this->DAT_SomeTile] + & L_WALL_OR_GATEHOUSE) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_SEA + | L_ROCKY | L_WALL_OR_GATEHOUSE | L_BUILDING + | L_BOULDERS | L_PEBBLES | L_IRON | L_RIVER + | L_FARM_FIELD_WHEAT | L_FARM_FIELD_HOP + | L_FARM_FIELD_APPLE | L_FARM_FIELD_DAIRY + | L_KEEP_NON_MANOR_HOUSE | L_MARSH | L_OIL) + == 0) { + local_48 = 0; + this->WallOwnerLayer[this->DAT_SomeTile] + = this->WallOwnerLayer[this->DAT_SomeTile] + & 0xf7; + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + 4) + & L_WALL_OR_GATEHOUSE) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + -4) + & L_WALL_OR_GATEHOUSE) + != 0) { + bVar19 = bVar19 | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 1; + } + if ((puVar18[1] & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*puVar18 & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 4; + } + if ((puVar18[1] & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 0x10; + } + if ((*puVar18 & L_WALL_OR_GATEHOUSE) != 0) { + bVar19 = bVar19 | 8; + } + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + 4) + & 2) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + -4) + & 2) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 1; + } + if ((puVar18[1] & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 0x40; + } + if ((*puVar18 & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 4; + } + if ((puVar18[1] & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 0x10; + } + if ((*puVar18 & L_STOCKPILEUnk) != 0) { + this->bitFlag = this->bitFlag | 8; + } + bVar19 = ~this->bitFlag & bVar19; + if (bVar19 != 0) { + switch (bVar19 & 0xaa) { + case 10: + local_48 = 2; + if ((bVar19 & 0x15) == 0x15) { + local_48 = 0; + } + break; + case 0x28: + local_48 = (uint)((bVar19 & 0x54) != 0x54); + break; + case 0x82: + local_48 = 3; + if ((bVar19 & 0x45) == 0x45) { + local_48 = 0; + } + break; + case 0xa0: + local_48 = 4; + if ((bVar19 & 0x41) == 0x15) { + local_48 = 0; + } + } + if (local_48 != 0) { + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + 4) + & 0x800) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + -4) + & 0x800) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 1; + } + if ((puVar18[1] & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 0x40; + } + if ((*puVar18 & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 4; + } + if ((puVar18[1] & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 0x10; + } + if ((*puVar18 & L_STAIRS) != 0) { + this->bitFlag = this->bitFlag | 8; + } + if (this->bitFlag != 0) { + local_48 = 0; + } + } + if (local_48 != 0) { + /* the corner picks its two cardinal neighbours and the diagonal between them + (the decompiler lost these four arms: they are the jump table at 0x00510d94) */ + switch (local_48) { + case 1: + local_68 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][2]; + local_60 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][4]; + local_54 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][3]; + break; + case 2: + local_68 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][6]; + local_60 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][4]; + local_54 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][5]; + break; + case 3: + local_68 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][6]; + local_60 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][0]; + local_54 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][7]; + break; + case 4: + local_68 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][2]; + local_60 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][0]; + local_54 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][1]; + break; + } + bVar19 = this->HeightLayer[local_68]; + bVar16 = this->HeightLayer[local_60]; + bVar7 = this->HeightLayer[local_54]; + if ((this->LogicLayer[local_54] & 0x100U) + == 0) { + bVar7 = bVar16; + } + bVar6 = bVar16; + if (bVar19 < bVar16) { + bVar6 = bVar19; + } + if ((bVar6 < bVar7) + && (bVar7 = bVar16, bVar19 < bVar16)) { + bVar7 = bVar19; + } + if (this->HeightLayer[this->DAT_SomeTile] + < bVar7) { + this->WallGFXLayer[this->DAT_SomeTile] + = (ushort)bVar7; + if (((this->DamageLayer[local_68] != 0) + || (this->DamageLayer[local_60] + != 0)) + || (( + this->DamageLayer[local_54] != 0 + && ((this->LogicLayer[local_54] + & 0x100U) + != 0)))) { + this->WallOwnerLayer[this + ->DAT_SomeTile] + = this->WallOwnerLayer[this + ->DAT_SomeTile] + | 8; + } + } else { + local_48 = 0; + } + if (local_48 != 0) { + uVar12 = (local_48 + 3) + - this->mapOrientation / 2 + & 0x80000003; + if ((int)uVar12 < 0) { + uVar12 + = (uVar12 - 1 | 0xfffffffc) + 1; + } + switch (uVar12) { + case 0: + this->MiscDisplayLayer[this + ->DAT_SomeTile] + = this->MiscDisplayLayer[this + ->DAT_SomeTile] + | 0x40; + this->AlphaGFXLayer[this + ->DAT_SomeTile] = 0x2f; + break; + case 1: + this->MiscDisplayLayer[this + ->DAT_SomeTile] + = this->MiscDisplayLayer[this + ->DAT_SomeTile] + | 0x200; + this->AlphaGFXLayer[this + ->DAT_SomeTile] = 0x2e; + break; + case 2: + this->MiscDisplayLayer[this + ->DAT_SomeTile] + = this->MiscDisplayLayer[this + ->DAT_SomeTile] + | 0x80; + this->AlphaGFXLayer[this + ->DAT_SomeTile] = 0x31; + break; + case 3: + this->MiscDisplayLayer[this + ->DAT_SomeTile] + = this->MiscDisplayLayer[this + ->DAT_SomeTile] + | 0x100; + this->AlphaGFXLayer[this + ->DAT_SomeTile] = 0x30; + } + } + } + } + } + } else { + this->field112_0x554908 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + computeWallCornerRenderRotation, + this)(iVar17); + this->WallGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[10] + -1 + + (short)this->field112_0x554908; + sVar4 = (short)GMTotalPicturesProcessed::instance[0xc]; + if (this->DamageLayer[this->DAT_SomeTile] == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & 0x200U) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] + & 0x800U) + == 0) { + if (this->LuminesenceLayer[this + ->DAT_SomeTile] + < 4) { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x60 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 7); + } else { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x68 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 7); + } + } else { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + hasHigherNeighborWithStairs, + this)( + this->DAT_SomeTile, this->DAT_SomeY, 0); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + hasHigherNeighborWithStairs, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 2); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + hasHigherNeighborWithStairs, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 4); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + hasHigherNeighborWithStairs, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 6); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + hasHigherPlainNeighborWithWallOrGatehouse, + this)( + this->DAT_SomeTile, + this->DAT_SomeY, 0); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + hasHigherPlainNeighborWithWallOrGatehouse, + this)( + this->DAT_SomeTile, + this->DAT_SomeY, 2); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + hasHigherPlainNeighborWithWallOrGatehouse, + this)( + this->DAT_SomeTile, + this->DAT_SomeY, + 4); + if (BVar11 + == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + hasHigherPlainNeighborWithWallOrGatehouse, + this)( + this->DAT_SomeTile, + this->DAT_SomeY, + 6); + if (BVar11 + == FALSE) { + this->GfxLayer + [this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance + [0xc] + + 0x68; + } else { + this->GfxLayer + [this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance + [0xc] + + 0x85; + } + } else { + this->GfxLayer + [this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance + [0xc] + + 0x88; + } + } else { + this->GfxLayer[this + ->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance + [0xc] + + 0x87; + } + } else { + this->GfxLayer[this + ->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed:: + instance + [0xc] + + 0x86; + } + } else { + this->GfxLayer[this + ->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed:: + instance[0xc] + + 0x85; + } + } else { + this->GfxLayer[this + ->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed:: + instance[0xc] + + 0x88; + } + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed:: + instance[0xc] + + 0x87; + } + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance[0xc] + + 0x86; + } + } + } else { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + isWallCornerForCardinalDirection, + this)( + this->DAT_SomeTile, this->DAT_SomeY, 0); + if (BVar11 == FALSE) { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + isWallCornerForCardinalDirection, + this)( + this->DAT_SomeTile, this->DAT_SomeY, 2); + if (BVar11 == FALSE) { + uVar12 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + isWallCornerForDiagonalDirection, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 1); + if (uVar12 == 0) { + uVar12 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + isWallCornerForDiagonalDirection, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 3); + if (uVar12 == 0) { + uVar12 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + isWallCornerForDiagonalDirection, + this)(this->DAT_SomeTile, + this->DAT_SomeY, 5); + if (uVar12 == 0) { + uVar12 = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + isWallCornerForDiagonalDirection, + this)( + this->DAT_SomeTile, + this->DAT_SomeY, 7); + sVar4 = (short) + GMTotalPicturesProcessed:: + instance[0xc]; + if (uVar12 == 0) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x84; + this->LogicLayer[this + ->DAT_SomeTile] + = this->LogicLayer + [this->DAT_SomeTile] + | 0x400000; + } else { + if (this->mapOrientation + == 0) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x81; + } else if ( + this->mapOrientation + == 2) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x80; + } else if ( + this->mapOrientation + == 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x83; + } else if ( + this->mapOrientation + == 6) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x82; + } + this->LogicLayer[this + ->DAT_SomeTile] + = this->LogicLayer + [this->DAT_SomeTile] + | 0x400000; + } + } else { + sVar4 = (short) + GMTotalPicturesProcessed:: + instance[0xc]; + if (this->mapOrientation + == 0) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x80; + } else if ( + this->mapOrientation + == 2) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x83; + } else if ( + this->mapOrientation + == 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x82; + } else if ( + this->mapOrientation + == 6) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x81; + } + this->LogicLayer[this + ->DAT_SomeTile] + = this->LogicLayer[this + ->DAT_SomeTile] + | 0x400000; + } + } else { + sVar4 = (short) + GMTotalPicturesProcessed:: + instance[0xc]; + if (this->mapOrientation == 0) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x83; + } else if (this->mapOrientation + == 2) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x82; + } else if (this->mapOrientation + == 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x81; + } else if (this->mapOrientation + == 6) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x80; + } + this->LogicLayer[this + ->DAT_SomeTile] + = this->LogicLayer[this + ->DAT_SomeTile] + | 0x400000; + } + } else { + sVar4 = (short) + GMTotalPicturesProcessed:: + instance[0xc]; + if (this->mapOrientation == 0) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x82; + } else if (this->mapOrientation + == 2) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x81; + } else if (this->mapOrientation + == 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x80; + } else if (this->mapOrientation + == 6) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x83; + } + this->LogicLayer[this->DAT_SomeTile] + = this->LogicLayer[this + ->DAT_SomeTile] + | 0x400000; + } + } else { + sVar4 + = (short)GMTotalPicturesProcessed:: + instance[0xc]; + if ((this->mapOrientation == 0) + || (this->mapOrientation == 4)) { + if ((this->LogicLayer[this + ->DAT_SomeTile] + & 0x400000U) + == 0) { + this->GfxLayer[this + ->DAT_SomeTile] = sVar4 + + 0x70 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else { + this->GfxLayer[this + ->DAT_SomeTile] = sVar4 + + 0x78 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } + } else if ((this->LogicLayer[this + ->DAT_SomeTile] + & 0x400000U) + == 0) { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x74 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x7c + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } + } + } else { + sVar4 = (short) + GMTotalPicturesProcessed::instance[0xc]; + if ((this->mapOrientation == 0) + || (this->mapOrientation == 4)) { + if ((this->LogicLayer[this + ->DAT_SomeTile] + & 0x400000U) + == 0) { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x74 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x7c + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } + } else if ((this->LogicLayer[this + ->DAT_SomeTile] + & 0x400000U) + == 0) { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x70 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else { + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x78 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } + } + } + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x8a + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } + } + } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeClimbRampRotation, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xe] + 0x25 + + (this->RandomLayer[this->DAT_SomeTile] & 1) * 9; + DAT_BuildingsState::instance.field14_0x18e024 = 1; + } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeClimbRampRotation, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + this->GfxLayer[this->DAT_SomeTile] + = (this->RandomLayer[this->DAT_SomeTile] & 3) + + (short)GMTotalPicturesProcessed::instance[0xe]; + DAT_BuildingsState::instance.field14_0x18e024 = 1; + } + } else { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isTileSuitableForBrushPlacement, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + if (BVar11 == FALSE) { + this->PillarGFXLayer[this->DAT_SomeTile] = 0x20; + } else { + this->PillarGFXLayer[this->DAT_SomeTile] + = (this->RandomLayer[this->DAT_SomeTile] & 0xf) + 0x23; + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x29c; + } + } else { + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isTileSuitableForBrushPlacement, this)( + this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + if (BVar11 == FALSE) { + this->PillarGFXLayer[this->DAT_SomeTile] = 0x20; + } else { + this->PillarGFXLayer[this->DAT_SomeTile] + = (this->RandomLayer[this->DAT_SomeTile] & 0xf) + 0x23; + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x214; + } + } else if (DAT_BuildingsState::instance + .buildings[this->BuildingLayer[this->DAT_SomeTile]] + .buildingType + == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::computeTileLuminescence, + this)(this->DAT_SomeTile, this->DAT_SomeY); + } + } + this->DAT_SomeX = this->DAT_SomeX + 1; + } + } + } + } + } + local_c = DAT_PathFindingState::instance.mappingYRelated % 10; + for (local_18 = this->someIndex; local_18 <= this->someLimit; local_18 = local_18 + 1) { + for (local_10 = this->someYLike; local_10 <= this->someYLikeLimit; local_10 = local_10 + 1) { + if (*(char*)(local_18 * 0x28 + 0x1f93438 + local_10) != '\0') { + local_24 = local_c; + local_c = 0; + for (; local_24 < 10; local_24 = local_24 + 1) { + this->DAT_SomeY = local_18 * 10 + local_24; + this->DAT_SomeX = local_10 * 10; + for (local_30 = 0; local_30 < 10; local_30 = local_30 + 1) { + BVar11 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, (uint)((int)(this->DAT_SomeY))); + if ((((BVar11 != FALSE) + && (this->DAT_SomeTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY), + (this->LogicLayer[this->DAT_SomeTile] & 0x100201U) != 0)) + && (this->ChangedLayer[this->DAT_SomeTile] != 0)) + && ((this->BuildingLayer[this->DAT_SomeTile] == 0 + && ((this->LogicLayer[this->DAT_SomeTile] & 0x10000030U) == 0)))) { + if ((this->LogicLayer[this->DAT_SomeTile] & 1U) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & 0x100000U) != 0) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeTileCliffEdgeFlags, this)( + this->DAT_SomeTile, this->DAT_SomeX, this->DAT_SomeY); + } + } else { + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xfffc; + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][this->mapOrientation]; + this->field218_0x554a50 = (ushort)this->HeightLayer[iVar17]; + if ((this->LogicLayer[iVar17] & 1U) != 0) { + this->field218_0x554a50 = 0; + } + if ((this->LogicLayer[iVar17] & 0x80U) != 0) { + this->field218_0x554a50 = 0x14; + } + if (0x13 < this->field218_0x554a50) { + sVar4 = (short)GMTotalPicturesProcessed::instance[0xa6]; + if (this->field218_0x554a50 < 0x5b) { + if (this->field218_0x554a50 < 0x29) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x5dc; + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x5e2; + } + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x5ee; + } + this->PillarGFXLayer[this->DAT_SomeTile] + = (ushort)GMTotalPicturesProcessed::instance[9]; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x40; + } + local_74 = 0; + this->bitFlag = 0; + for (local_70 = 0; local_70 < 8; local_70 = local_70 + 1) { + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][local_70]; + if (this->HeightLayer[iVar17] < 0x14) { + if ((this->LogicLayer[iVar17] & 0x100031U) == 0) { + this->bitFlag + = this->bitFlag | (byte)(0x80 >> ((byte)local_70 & 0x1f)); + } + if (((this->LogicLayer[iVar17] & 0x100001U) == 0) + && ((this->Logic2Layer[iVar17] & 0x20) != 0)) { + local_74 = 0x80 >> ((byte)local_70 & 0x1f) | local_74; + } + } + } + if (this->bitFlag != 0) { + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x100; + this->CertainPathLayer[this->DAT_SomeTile] + = (ushort)this->bitFlag | (ushort)(local_74 << 8); + } + } + if ((this->LogicLayer[this->DAT_SomeTile] & 0x200U) != 0) { + uVar12 = this->field84_0x5548a4 + 7U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + uVar12 = this->field84_0x5548a4 + 1U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + if (((((this->LogicLayer[iVar17] | this->LogicLayer[iVar13]) & 1U) == 0) + && ((this->MiscDisplayLayer[iVar17] & 0x3c0) != 0)) + && ((this->MiscDisplayLayer[iVar13] & 0x3c0) != 0)) { + if (this->LuminesenceLayer[this->DAT_SomeTile] < 4) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x60 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x68 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } + } + uVar12 = this->field84_0x5548a4 + 1U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + uVar12 = this->field84_0x5548a4 + 3U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + if (((((this->LogicLayer[iVar17] | this->LogicLayer[iVar13]) & 1U) == 0) + && ((this->MiscDisplayLayer[iVar17] & 0x3c0) != 0)) + && ((this->MiscDisplayLayer[iVar13] & 0x3c0) != 0)) { + if ((this->DAT_SomeY & 1U) == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x138; + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x137; + } + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x3c0; + } + uVar12 = this->field84_0x5548a4 + 5U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + uVar12 = this->field84_0x5548a4 + 7U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + if (((((this->LogicLayer[iVar17] | this->LogicLayer[iVar13]) & 1U) == 0) + && ((this->MiscDisplayLayer[iVar17] & 0x3c0) != 0)) + && ((this->MiscDisplayLayer[iVar13] & 0x3c0) != 0)) { + if ((this->DAT_SomeY & 1U) == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x13a; + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x139; + } + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x3c0; + } + uVar12 = this->field84_0x5548a4 + 3U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar17 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + uVar12 = this->field84_0x5548a4 + 5U & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix[this->DAT_SomeY][uVar12]; + if (((((this->LogicLayer[iVar17] | this->LogicLayer[iVar13]) & 1U) == 0) + && ((this->MiscDisplayLayer[iVar17] & 0x3c0) != 0)) + && ((this->MiscDisplayLayer[iVar13] & 0x3c0) != 0)) { + uVar12 = this->DAT_SomeY & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + 0x12f + + (short)uVar12; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x3c0; + } + } + } + this->DAT_SomeX = this->DAT_SomeX + 1; + } + } + } + } + } + local_c = DAT_PathFindingState::instance.mappingYRelated % 10; + for (local_18 = this->someIndex; local_18 <= this->someLimit; local_18 = local_18 + 1) { + for (local_10 = this->someYLike; local_10 <= this->someYLikeLimit; local_10 = local_10 + 1) { + if (*(char*)(local_18 * 0x28 + 0x1f93438 + local_10) != '\0') { + local_24 = local_c; + local_c = 0; + for (; local_24 < 10; local_24 = local_24 + 1) { + this->DAT_SomeY = local_18 * 10 + local_24; + this->DAT_SomeX = local_10 * 10; + for (local_30 = 0; local_30 < 10; local_30 = local_30 + 1) { + BVar11 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, (uint)((int)(this->DAT_SomeY))); + if (((BVar11 != FALSE) + && (this->DAT_SomeTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY), + (this->LogicLayer[this->DAT_SomeTile] & 1U) != 0)) + && (((this->ChangedLayer[this->DAT_SomeTile] != 0 + && (((this->LogicLayer[this->DAT_SomeTile] & 0x10000030U) == 0 + && (this->BuildingLayer[this->DAT_SomeTile] == 0)))) + && ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0x40) == 0)))) { + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + 2) & 0x80) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + -2) & 0x80) + != 0) { + bVar19 = bVar19 | 2; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + this->DAT_SomeY * 0x20) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x80) != 0) { + bVar19 = bVar19 | 1; + } + if ((*(uint*)((int)puVar18 + 2) & 0x80) != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*puVar18 & 0x80) != 0) { + bVar19 = bVar19 | 0x80; + } + bVar16 = 0; + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + 2) & 0x40) + != 0) { + bVar16 = 0x20; + } + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + -2) & 0x40) + != 0) { + bVar16 = bVar16 | 2; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + this->DAT_SomeY * 0x20) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x40) != 0) { + bVar16 = bVar16 | 1; + } + if ((*(uint*)((int)puVar18 + 2) & 0x40) != 0) { + bVar16 = bVar16 | 0x40; + } + if ((*puVar18 & 0x40) != 0) { + bVar16 = bVar16 | 0x80; + } + this->bitFlag = bVar16 & ~bVar19; + if (this->bitFlag != 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xa6] + 0x5d0; + this->PillarGFXLayer[this->DAT_SomeTile] + = (ushort)GMTotalPicturesProcessed::instance[9]; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x80; + } + } + this->DAT_SomeX = this->DAT_SomeX + 1; + } + } + } + } + } + local_c = DAT_PathFindingState::instance.mappingYRelated % 10; + for (local_18 = this->someIndex; local_18 <= this->someLimit; local_18 = local_18 + 1) { + for (local_10 = this->someYLike; local_10 <= this->someYLikeLimit; local_10 = local_10 + 1) { + if (*(char*)(local_18 * 0x28 + 0x1f93438 + local_10) != '\0') { + local_24 = local_c; + local_c = 0; + for (; local_24 < 10; local_24 = local_24 + 1) { + this->DAT_SomeY = local_18 * 10 + local_24; + this->DAT_SomeX = local_10 * 10; + for (local_30 = 0; local_30 < 10; local_30 = local_30 + 1) { + BVar11 = MACRO_CALL_MEMBER(OpenSHC::Rendering::ViewportRenderState_Func::xyAreValid, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, (uint)((int)(this->DAT_SomeY))); + if (((BVar11 != FALSE) + && (this->DAT_SomeTile = MACRO_CALL_MEMBER( + OpenSHC::Rendering::ViewportRenderState_Func::translateXYToTile, + DAT_ViewportRenderState::ptr)(this->DAT_SomeX, this->DAT_SomeY), + (this->LogicLayer[this->DAT_SomeTile] & L_BORDER | L_BORDER_EDGE) == 0)) + && (this->ChangedLayer[this->DAT_SomeTile] != 0)) { + this->ChangedLayer[this->DAT_SomeTile] = this->ChangedLayer[this->DAT_SomeTile] - 1; + iVar17 = this->DAT_SomeX; + if ((this->LogicLayer[this->DAT_SomeTile] & L_SEA) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_RIVER) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_FORD) == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_PLAIN2_AND_PITCH) == 0) { + if (this->BuildingLayer[this->DAT_SomeTile] != 0) { + iVar13 = (int)this->BuildingLayer[this->DAT_SomeTile]; + if (DAT_BuildingsState::instance.buildings[iVar13].buildingType + == OpenSHC::Map::Buildings::BT_STOCKPILE) { + this->field112_0x554908 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + computeWallCornerRenderRotation, + this)(this->DAT_SomeX); + this->WallGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[10] + -1 + + (short)this->field112_0x554908; + } + iVar14 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeClimbRampRotation, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + BVar1 = DAT_BuildingsState::instance.buildings[iVar13] + .buildingType; + if (((BVar1 == OpenSHC::Map::Buildings::BT_FIREBALLISTA) + || ((0x4f < (short)BVar1 && ((short)BVar1 < 0x55)))) + && (iVar14 == 0)) { + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)(((((int)(uint)this + ->HeightLayer[this->DAT_SomeTile] + >> 3) + + -1) + * 0x40) + / 2) + + (short)GMTotalPicturesProcessed::instance[3] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else { + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + } + if (((DAT_BuildingsState::instance.buildings[iVar13] + .buildingType + == OpenSHC::Map::Buildings::BT_KILLINGPIT) + && (DAT_BuildingsState::instance.buildings[iVar13].state + < 1)) + && (( + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::isSameTeam, + DAT_GameState::ptr)( + (int)DAT_BuildingsState::instance.buildings[iVar13] + .owner, + (int)((int)(DAT_GameSynchronyState::instance + .currentPlayerSlotID))), + BVar11 == FALSE + && (DAT_GameCore::instance.gameMode_2 + != OpenSHC::Game::GM_EDITOR)))) { + if ((this->LogicLayer[this->DAT_SomeTile] + & L_DEFAULT_EARTH_OR_TEXTURE) + == 0) + goto LAB_00510585; + this->GfxLayer[this->DAT_SomeTile] = 0; + } else { + if (DAT_BuildingsState::instance.buildings[iVar13] + .buildingType + == OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) + goto LAB_00510585; + if (DAT_BuildingsState::instance.buildings[iVar13] + .currentTilePositionAdjusted + == this->DAT_SomeTile) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + updateBuildingGraphicsLayer, + this)(iVar13); + goto LAB_005109e8; + } + } + goto LAB_0050c199; + } + if ((this->LogicLayer[this->DAT_SomeTile] & L_KEEP_NON_MANOR_HOUSE) + == 0) { + if (((this->LogicLayer[this->DAT_SomeTile] & L_ROCKY) == 0) + || ((this->LogicLayer[this->DAT_SomeTile] + & L_WALL_OR_GATEHOUSE) + != 0)) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_BOULDERS) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_PEBBLES) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] & L_IRON) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] + & L_OIL) + == 0) { + if ((this->LogicLayer[this->DAT_SomeTile] + & L_MOAT) + == 0) { + if (((this->LogicLayer[this + ->DAT_SomeTile] + & L_WALL_OR_GATEHOUSE + | L_FARM_FIELD_WHEAT + | L_FARM_FIELD_HOP + | L_FARM_FIELD_APPLE + | L_FARM_FIELD_DAIRY) + == 0) + || ((this->LogicLayer[this + ->DAT_SomeTile] + & L_FARM_FIELD_APPLE) + != 0)) { + sVar8 = 0; + if ((this->WallOwnerLayer[this + ->DAT_SomeTile] + & 8) + != 0) { + sVar8 = 0x2d; + } + if ((this->MiscDisplayLayer[this + ->DAT_SomeTile] + & 0x80) + != 0) + goto LAB_0050ffbc; + if ((((this->LogicLayer[this + ->DAT_SomeTile] + & L_WALL_OR_GATEHOUSE + | L_BUILDING + | L_KEEP_NON_MANOR_HOUSE) + != 0) + || (this->BuildingWasLayer + [this->DAT_SomeTile] + == '\0')) + || ((this->MiscDisplayLayer[this + ->DAT_SomeTile] + & 0x10) + == 0)) + goto LAB_00510585; + } + } else { + this->bitFlag = 0; + for (local_d4 = 0; local_d4 < 8; + local_d4 = local_d4 + 2) { + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix + [this->DAT_SomeY] + [local_d4]; + if ((this->LogicLayer[iVar13] + & L_MOAT) + == 0) { + if (((this->BuildingLayer + [iVar13] + != 0) + && (DAT_BuildingsState::instance + .buildings[this->BuildingLayer + [iVar13]] + .buildingType + == OpenSHC::Map:: + Buildings:: + BT_DRAWBRIDGE)) + && (iVar13 + = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + returnOwnedMoatAtTile, + this)(iVar13), + iVar13 != 0)) { + this->bitFlag + = this->bitFlag + | (byte)(0x80 + >> ((byte)local_d4 + & 0x1f)); + } + } else { + this->bitFlag = this->bitFlag + | (byte)(0x80 + >> ((byte)local_d4 + & 0x1f)); + } + } + this->bitFlag = ~this->bitFlag & 0xaa; + if (this->bitFlag == 0) { + this->bitFlag = 0; + for (local_d4 = 1; local_d4 < 8; + local_d4 = local_d4 + 2) { + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix + [this->DAT_SomeY] + [local_d4]; + if ((this->LogicLayer[iVar13] + & L_MOAT) + == 0) { + if (((this->BuildingLayer + [iVar13] + != 0) + && (DAT_BuildingsState::instance + .buildings + [this->BuildingLayer + [iVar13]] + .buildingType + == OpenSHC::Map:: + Buildings:: + BT_DRAWBRIDGE)) + && (iVar13 + = MACRO_CALL_MEMBER( + OpenSHC::Map:: + TileMapState_Func:: + returnOwnedMoatAtTile, + this)(iVar13), + iVar13 != 0)) { + this->bitFlag + = this->bitFlag + | (byte)(0x80 + >> ((byte) + local_d4 + & 0x1f)); + } + } else { + this->bitFlag + = this->bitFlag + | (byte)(0x80 + >> ((byte)local_d4 + & 0x1f)); + } + } + this->bitFlag + = ~this->bitFlag & 0x55; + } + if (this->mapOrientation == 0) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation:: + DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState:: + ptr)(this->bitFlag, 0); + } else if (this->mapOrientation == 2) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation:: + DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState:: + ptr)(this->bitFlag, 2); + } else if (this->mapOrientation == 4) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation:: + DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState:: + ptr)(this->bitFlag, 4); + } else if (this->mapOrientation == 6) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation:: + DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState:: + ptr)(this->bitFlag, 6); + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance[5] + + 0xcc + + (ushort)this->LuminesenceLayer + [this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + for (local_14 = 0; local_14 < 7; + local_14 = local_14 + 1) { + if (DAT_TerrainDefinedData::instance + .field2298_0x1d64[local_14] + .unk1 + == this->bitFlag) { + sVar4 = (short) + GMTotalPicturesProcessed:: + instance[5]; + if (local_14 < 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0xec + + (ushort)this->LuminesenceLayer + [this->DAT_SomeTile] + * 4 + + (ushort)DAT_TerrainDefinedData:: + instance + .field2298_0x1d64 + [local_14] + .unk2; + } else if (local_14 == 4) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x10c + + (ushort)this->LuminesenceLayer + [this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else if (local_14 == 5) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 300 + + (ushort)this->LuminesenceLayer + [this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this + ->DAT_SomeTile] + & 3); + } else if (local_14 == 6) { + this->GfxLayer[this + ->DAT_SomeTile] + = sVar4 + 0x14c + + (ushort)this->LuminesenceLayer + [this->DAT_SomeTile]; + } + break; + } + } + if ((this->MiscDisplayLayer[this + ->DAT_SomeTile] + & 0x80) + != 0) { + LAB_0050ffbc: + uVar12 = 0xdU - this->mapOrientation + & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 + = (uVar12 - 1 | 0xfffffff8) + + 1; + } + uVar15 = 9U - this->mapOrientation + & 0x80000007; + if ((int)uVar15 < 0) { + uVar15 + = (uVar15 - 1 | 0xfffffff8) + + 1; + } + iVar13 = this->DAT_SomeTile + + this->directionTranslationMatrix + [this->DAT_SomeY][uVar15]; + uVar2 = (ushort)iVar17; + uVar3 = (ushort)this->DAT_SomeY; + if ((this->MiscDisplayLayer[this->DAT_SomeTile + + this + ->directionTranslationMatrix + [this->DAT_SomeY] + [uVar12]] + & 0x80) + == 0) { + if ((this->MiscDisplayLayer + [iVar13] + & 0x80) + == 0) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = this->AlphaGFXLayer[this + ->DAT_SomeTile] + + ((uVar2 ^ uVar3) & 1); + } else if ((this->mapOrientation + == 0) + || (this->mapOrientation + == 4)) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = ((uVar2 ^ uVar3) & 1) + + 0x33 + sVar8; + } else { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = ((uVar2 ^ uVar3) & 1) + + 0x35 + sVar8; + } + } else if ((this->MiscDisplayLayer + [iVar13] + & 0x80) + == 0) { + if ((this->mapOrientation == 0) + || (this->mapOrientation + == 4)) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = ((uVar2 ^ uVar3) & 1) + + 0x35 + sVar8; + } else { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = ((uVar2 ^ uVar3) & 1) + + 0x33 + sVar8; + } + } else if ((this->mapOrientation + == 0) + || (this->mapOrientation + == 6)) { + uVar12 = this->DAT_SomeY + & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 + | 0xfffffff8) + + 1; + } + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = (0x3e - (short)uVar12) + + sVar8; + } else { + uVar12 = this->DAT_SomeY + & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 + | 0xfffffff8) + + 1; + } + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = (short)uVar12 + 0x37 + + sVar8; + } + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + + 4) + & 0x200) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + this->DAT_SomeTile * 4 + + -4) + & 0x200) + != 0) { + this->bitFlag + = this->bitFlag | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 1; + } + if ((puVar18[1] & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 0x40; + } + if ((*puVar18 & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY + * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 4; + } + if ((puVar18[1] & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 0x10; + } + if ((*puVar18 & 0x200) != 0) { + this->bitFlag + = this->bitFlag | 8; + } + if (this->bitFlag != 0) { + switch (this->mapOrientation) { + case 0: + if ((this->bitFlag & 0x82) + == 0x82) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = this->AlphaGFXLayer + [this->DAT_SomeTile] + + 0xe; + } + break; + case 2: + if ((this->bitFlag & 0xa0) + == 0xa0) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = this->AlphaGFXLayer + [this->DAT_SomeTile] + + 0xe; + } + break; + case 4: + if ((this->bitFlag & 0x28) + == 0x28) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = this->AlphaGFXLayer + [this->DAT_SomeTile] + + 0xe; + } + break; + case 6: + if ((this->bitFlag & 10) + == 10) { + this->AlphaGFXLayer[this + ->DAT_SomeTile] + = this->AlphaGFXLayer + [this->DAT_SomeTile] + + 0xe; + } + } + } + if ((this->LogicLayer[this + ->DAT_SomeTile] + & L_PLAIN2_AND_PITCH + | L_MOAT) + == 0) + goto LAB_00510585; + } + } + } else { + this->PillarGFXLayer[this + ->DAT_SomeTile] = (ushort) + GMTotalPicturesProcessed::instance[9]; + this->field112_0x554908 + = (int)(short)this + ->RandomLayer[this->DAT_SomeTile] + & 7; + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed:: + instance[0x37] + + 0x428 + + (short)(this->field112_0x554908 << 4); + sVar4 = (short)this->DAT_SomeY; + sVar5 = (short)this->DAT_SomeX; + if (this->field112_0x554908 == 0) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x1ff; + } else if (this->field112_0x554908 == 1) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x1ff; + } else if (this->field112_0x554908 == 2) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x7f; + } else if (this->field112_0x554908 == 3) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x7f; + } else if (this->field112_0x554908 == 4) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0xff; + } else if (this->field112_0x554908 == 5) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0xff; + } else if (this->field112_0x554908 == 6) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x7f; + } else if (this->field112_0x554908 == 7) { + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this + ->DAT_SomeTile] + + sVar5 + sVar4 + & 0x7f; + } + } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func:: + computeClimbRampRotation, + this)(this->DAT_SomeTile, + (uint)((int)(this->DAT_SomeX)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short) + GMTotalPicturesProcessed::instance[9] + + -1 + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] + | 0x800; + this->field112_0x554908 + = (int)(short)this + ->RandomLayer[this->DAT_SomeTile] + & 0xf; + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance + [0xc] + + 0xee + (short)this->field112_0x554908; + } + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + computeClimbRampRotation, + this)(this->DAT_SomeTile, + (uint)((int)(this->DAT_SomeX)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + + -1 + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] + | 0x800; + this->field112_0x554908 + = (int)(short)this + ->RandomLayer[this->DAT_SomeTile] + & 0xf; + if (this->LuminesenceLayer[this->DAT_SomeTile] + < 6) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance + [0xc] + + 0x20 + (short)this->field112_0x554908; + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance + [0xc] + + 0x30 + (short)this->field112_0x554908; + } + } + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + computeClimbRampRotation, + this)(this->DAT_SomeTile, + (uint)((int)(this->DAT_SomeX)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] + | 0x800; + this->field112_0x554908 + = (int)(short)this->RandomLayer[this->DAT_SomeTile] + & 0xf; + if (this->LuminesenceLayer[this->DAT_SomeTile] < 6) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + + 0x40 + (short)this->field112_0x554908; + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xc] + + 0x50 + (short)this->field112_0x554908; + } + } + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + computeClimbRampRotation, + this)(this->DAT_SomeTile, + (uint)((int)(this->DAT_SomeX)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + iVar13 = (int)this->OrganismLayer[this->DAT_SomeTile]; + if (1999 < iVar13) { + if (*(int*)(&DAT_LandscapeState::instance.trees[0x635] + .unknownDistanceRelatedToCrow + + iVar13 * 0x10) + == this->DAT_SomeTile) { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + applyRockGraphicsToFootprint, + this)(iVar13 + -2000); + } + goto LAB_0050c199; + } + this->field112_0x554908 + = (int)(short)this->RandomLayer[this->DAT_SomeTile] & 7; + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0x38] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 8 + + (short)this->field112_0x554908; + } + } else { + if (DAT_BuildingsState::instance + .buildings[this->BuildingLayer[this->DAT_SomeTile]] + .currentTilePositionAdjusted + != this->DAT_SomeTile) + goto LAB_0050c199; + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + updateBuildingGraphicsLayer, + this)((int)this->BuildingLayer[this->DAT_SomeTile]); + } + } else { + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xdfff; + iVar13 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::getPitchDitchIDForTile, this)( + this->DAT_SomeTile); + if (iVar13 != 0) { + if (((this->pitchDitches[iVar13].state < 2) + && (BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func:: + isSameTeam, + DAT_GameState::ptr)( + (int)this->pitchDitches[iVar13].owner, + (int)((int)(DAT_GameSynchronyState::instance + .currentPlayerSlotID))), + BVar11 == FALSE)) + && (DAT_GameCore::instance.gameMode_2 + != OpenSHC::Game::GM_EDITOR)) { + if ((this->LogicLayer[this->DAT_SomeTile] + & L_DEFAULT_EARTH_OR_TEXTURE) + == 0) + goto LAB_00510585; + this->GfxLayer[this->DAT_SomeTile] = 0; + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func:: + computeClimbRampRotation, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + this->GfxLayer[this->DAT_SomeTile] + = (this->pitchDitches[iVar13].rng & 7U) + + (short)GMTotalPicturesProcessed::instance[0x8c]; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x2000; + if ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0x80) + != 0) + goto LAB_0050ffbc; + } + goto LAB_0050c199; + } + LAB_00510585: + uVar12 + = ((int)(uint)this->HeightLayer[this->DAT_SomeTile] >> 3) - 1U + & 0x8000000f; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff0) + 1; + } + local_8 = uVar12 * 0x40 + 1; + iVar13 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeClimbRampRotation, + this)(this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + if ((this->HeightLayer[this->DAT_SomeTile] < 0x88) + && (iVar13 == 0)) { + if (local_8 < 1) { + local_8 = 1; + } + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)((local_8 + -1) / 2) + + (short)GMTotalPicturesProcessed::instance[3] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + BVar11 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::isCliffDropInDirection, + this)(this->DAT_SomeTile, (undefined4)((int)(iVar17)), + this->DAT_SomeY); + if (BVar11 == FALSE) { + bVar10 = false; + } else { + bVar10 = true; + } + } else { + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[9] + -1 + + (short)this->field112_0x554908; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + bVar10 = true; + } + if ((this->Logic2Layer[this->DAT_SomeTile] & 0x20) == 0) { + if (this->HeightLayer[this->DAT_SomeTile] < 8) { + if ((this->Logic2Layer[this->DAT_SomeTile] & 2) == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[2] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0x37] + + 0xb4 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } + } else if ((this->LogicLayer[this->DAT_SomeTile] + & L_DEFAULT_EARTH_OR_TEXTURE) + == 0) { + if ((bVar10) + && (DAT_GameCore::instance.gameMode_2 + == OpenSHC::Game::GM_EDITOR)) { + this->LogicLayer[this->DAT_SomeTile] + = this->LogicLayer[this->DAT_SomeTile] | 128; + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0x38] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 8 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[2] + + ((short)((int)(uint)this + ->HeightLayer[this->DAT_SomeTile] + >> 3) + + -1) + * 0x20 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } + } else { + /* + sets section 1001 after placing oasis grass for example + */ + this->GfxLayer[this->DAT_SomeTile] = 0; + } + } else { + this->GfxLayer[this->DAT_SomeTile] = 0; + } + } + } else { + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) + & L_RIVER + | L_FORD) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + -4) + & L_RIVER + | L_FORD) + != 0) { + bVar19 = bVar19 | 2; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4) + & L_RIVER + | L_FORD) + != 0) { + bVar19 = bVar19 | 0x80; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4) + & L_RIVER + | L_FORD) + != 0) { + bVar19 = bVar19 | 8; + } + this->bitFlag = ~bVar19 & 0xaa; + if (this->bitFlag == 0) { + bVar19 = (*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4 + -4) + & L_RIVER + | L_FORD) + != 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4 + 4) + & 0x300000) + != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4 + -4) + & 0x300000) + != 0) { + bVar19 = bVar19 | 4; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4 + 4) + & 0x300000) + != 0) { + bVar19 = bVar19 | 0x10; + } + this->bitFlag = ~bVar19 & 0x55; + } + if (this->mapOrientation == 0) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 0); + } else if (this->mapOrientation == 2) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 2); + } else if (this->mapOrientation == 4) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 4); + } else if (this->mapOrientation == 6) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 6); + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x29c + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 8 + + (this->RandomLayer[this->DAT_SomeTile] & 7); + for (local_14 = 0; local_14 < 7; local_14 = local_14 + 1) { + if (DAT_TerrainDefinedData::instance.field2298_0x1d64[local_14].unk1 + == this->bitFlag) { + sVar4 = (short)GMTotalPicturesProcessed::instance[5]; + if (local_14 < 4) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x234 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (ushort)DAT_TerrainDefinedData::instance + .field2298_0x1d64[local_14] + .unk2; + } else if (local_14 == 4) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x254 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else if (local_14 == 5) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x274 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else if (local_14 == 6) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x294 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile]; + } + break; + } + } + } + } else { + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] & 0xf7; + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) & 1) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + -4) & 1) + != 0) { + bVar19 = bVar19 | 2; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4) + & 1) + != 0) { + bVar19 = bVar19 | 0x80; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4) + & 1) + != 0) { + bVar19 = bVar19 | 8; + } + if ((bVar19 != 0) + && (this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] | 8, + (this->Logic2Layer[this->DAT_SomeTile] & 0x20) != 0)) { + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] & 0xdf; + this->WallGFXLayer[this->DAT_SomeTile] + = this->RandomLayer[this->DAT_SomeTile] & 7; + } + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) & 0x100031) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + -4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 2; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 0x80; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 8; + } + this->bitFlag = ~bVar19 & 0xaa; + if (this->bitFlag == 0) { + bVar19 = (*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4 + -4) + & 0x100031) + != 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4 + 4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4 + -4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 4; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4 + 4) + & 0x100031) + != 0) { + bVar19 = bVar19 | 0x10; + } + this->bitFlag = ~bVar19 & 0x55; + } + if (this->mapOrientation == 0) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 0); + } else if (this->mapOrientation == 2) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 2); + } else if (this->mapOrientation == 4) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 4); + } else if (this->mapOrientation == 6) { + this->bitFlag = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + rotateByteLeft, + DAT_DirectionAlgorithmState::ptr)(this->bitFlag, 6); + } + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::propagateCliffEdgeFlagFromNeighbor, + this)(this->DAT_SomeTile, iVar17, this->DAT_SomeY); + if (this->Logic2Layer[this->DAT_SomeTile] == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x214 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + for (local_14 = 0; local_14 < 7; local_14 = local_14 + 1) { + if (DAT_TerrainDefinedData::instance.field2298_0x1d64[local_14].unk1 + == this->bitFlag) { + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) + & 0x200000) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + + -4) + & 0x200000) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4) + & 0x200000) + != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4) + & 0x200000) + != 0) { + this->bitFlag = this->bitFlag | 8; + } + sVar4 = (short)GMTotalPicturesProcessed::instance[5]; + if (local_14 < 4) { + if (this->bitFlag == 0) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x234 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (ushort)DAT_TerrainDefinedData::instance + .field2298_0x1d64[local_14] + .unk2; + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x2dc + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (ushort)DAT_TerrainDefinedData::instance + .field2298_0x1d64[local_14] + .unk2; + } + } else if (this->bitFlag == 0) { + if (local_14 == 4) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x254 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else if (local_14 == 5) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x274 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] + * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else if (local_14 == 6) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x294 + + (ushort)this + ->LuminesenceLayer[this->DAT_SomeTile]; + } + } + break; + } + } + } + if ((this->Logic2Layer[this->DAT_SomeTile] & 0x20) != 0) { + sVar4 = (this->WallGFXLayer[this->DAT_SomeTile] & 8) * 8 + 0x38d; + sVar5 = (short)GMTotalPicturesProcessed::instance[5]; + if (this->mapOrientation == 0) { + this->GfxLayer[this->DAT_SomeTile] = sVar5 + sVar4 + -1 + + (short)((int)(this->WallGFXLayer[this->DAT_SomeTile] & 0x3e0) + >> 5) + * 8; + } else if (this->mapOrientation == 2) { + this->GfxLayer[this->DAT_SomeTile] = sVar5 + sVar4 + -1 + + ((short)((int)(this->WallGFXLayer[this->DAT_SomeTile] & 0x3e0) + >> 5) + - 2U + & 7) + * 8; + } else if (this->mapOrientation == 4) { + this->GfxLayer[this->DAT_SomeTile] = sVar5 + sVar4 + -1 + + ((short)((int)(this->WallGFXLayer[this->DAT_SomeTile] & 0x3e0) + >> 5) + - 4U + & 7) + * 8; + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar5 + sVar4 + -1 + + ((short)((int)(this->WallGFXLayer[this->DAT_SomeTile] & 0x3e0) + >> 5) + - 6U + & 7) + * 8; + } + } + sVar4 = (short)GMTotalPicturesProcessed::instance[5]; + if ((this->Logic2Layer[this->DAT_SomeTile] & 0x50) == 0) { + if (((int)(char)this->Logic2Layer[this->DAT_SomeTile] & 0x88U) == 0) { + if ((this->Logic2Layer[this->DAT_SomeTile] & 1) == 0) { + if ((this->Logic2Layer[this->DAT_SomeTile] & 2) == 0) { + if ((this->Logic2Layer[this->DAT_SomeTile] & 4) != 0) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x41c; + } + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x414; + } + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x40c; + } + } else { + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) + & 1) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + -4) + & 1) + != 0) { + bVar19 = bVar19 | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 1) != 0) { + bVar19 = bVar19 | 1; + } + if ((puVar18[1] & 1) != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*puVar18 & 1) != 0) { + bVar19 = bVar19 | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 1) != 0) { + bVar19 = bVar19 | 4; + } + if ((puVar18[1] & 1) != 0) { + bVar19 = bVar19 | 0x10; + } + if ((*puVar18 & 1) != 0) { + bVar19 = bVar19 | 8; + } + bVar16 = 0; + if ((*(uint*)((char*)this->ptr_TerrainTypeTileMap + this->DAT_SomeTile + 1) + & 0x50) + != 0) { + bVar16 = 0x20; + } + if ((*(uint*)((char*)this->ptr_TerrainTypeTileMap + this->DAT_SomeTile + + -1) + & 0x50) + != 0) { + bVar16 = bVar16 | 2; + } + puVar18 = (uint*)((char*)this->ptr_TerrainTypeTileMap + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + this->DAT_SomeTile); + if ((*(uint*)((int)puVar18 + -1) & 0x50) != 0) { + bVar16 = bVar16 | 1; + } + if ((*(uint*)((int)puVar18 + 1) & 0x50) != 0) { + bVar16 = bVar16 | 0x40; + } + if ((*puVar18 & 0x50) != 0) { + bVar16 = bVar16 | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_TerrainTypeTileMap + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + + this->DAT_SomeTile); + if ((*(uint*)((int)puVar18 + -1) & 0x50) != 0) { + bVar16 = bVar16 | 4; + } + if ((*(uint*)((int)puVar18 + 1) & 0x50) != 0) { + bVar16 = bVar16 | 0x10; + } + if ((*puVar18 & 0x50) != 0) { + bVar16 = bVar16 | 8; + } + this->bitFlag = bVar16 | bVar19; + local_c0 = 0xffffffff; + if (this->bitFlag == 0) { + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) + & 0x100000) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + + -4) + & 0x100000) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 1; + } + if ((puVar18[1] & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 0x40; + } + if ((*puVar18 & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4); + if ((puVar18[-1] & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 4; + } + if ((puVar18[1] & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 0x10; + } + if ((*puVar18 & 0x100000) != 0) { + this->bitFlag = this->bitFlag | 8; + } + if (this->bitFlag != 0) { + for (local_14 = 0; local_14 < 8; local_14 = local_14 + 1) { + if ((((uint)this->bitFlag + & 1 << ((byte)local_14 & 0x1f)) + != 0) + && (this->HeightLayer[this->DAT_SomeTile + + this->directionTranslationMatrix + [this->DAT_SomeY] + [DAT_TerrainDefinedData::instance + .field2475_0x370c[local_14]]] + <= this->HeightLayer[this->DAT_SomeTile])) { + this->bitFlag = this->bitFlag + & ~(byte)(1 << ((byte)local_14 & 0x1f)); + } + } + if (this->bitFlag != 0) { + if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 2) == 0) { + if (this->bitFlag == 0x41) { + local_c0 = 4; + } else if (this->bitFlag == 0x50) { + local_c0 = 6; + } else if (this->bitFlag == 0x14) { + local_c0 = 0; + } else if (this->bitFlag == 5) { + local_c0 = 2; + } else if ((this->bitFlag & 0x40) + == 0) { + if ((this->bitFlag & 1) == 0) { + if ((this->bitFlag & 4) == 0) { + if ((this->bitFlag & 0x10) + != 0) { + local_c0 = 7; + } + } else { + local_c0 = 1; + } + } else { + local_c0 = 3; + } + } else { + local_c0 = 5; + } + } else if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 5) == 5) { + local_c0 = 2; + } else { + local_c0 = 2; + } + } else { + local_c0 = 1; + } + } else { + local_c0 = 3; + } + } else if ((this->bitFlag & 2) == 0) { + if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 0x14) == 0x14) { + local_c0 = 0; + } else { + local_c0 = 0; + } + } else { + local_c0 = 7; + } + } else { + local_c0 = 1; + } + } else if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 0x50) == 0x50) { + local_c0 = 6; + } else { + local_c0 = 6; + } + } else { + local_c0 = 5; + } + } else { + local_c0 = 7; + } + } else if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 2) == 0) { + if ((this->bitFlag & 0x41) == 0x41) { + local_c0 = 4; + } else { + local_c0 = 4; + } + } else { + local_c0 = 3; + } + } else { + local_c0 = 5; + } + local_c0 = (local_c0 - this->mapOrientation) + 8 + & 0x80000007; + if ((int)local_c0 < 0) { + local_c0 = (local_c0 - 1 | 0xfffffff8) + 1; + } + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x30c + (short)(local_c0 << 4); + } + } + if (local_c0 == 0xffffffff) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x214 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] & 0x7f; + } + } else { + if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 2) == 0) { + if (this->bitFlag == 0x40) { + local_c0 = 5; + } else if (this->bitFlag == 1) { + local_c0 = 3; + } else if (this->bitFlag == 4) { + local_c0 = 1; + } else if (this->bitFlag == 0x10) { + local_c0 = 7; + } else if (this->bitFlag == 0x41) { + local_c0 = 4; + } else if (this->bitFlag == 0x50) { + local_c0 = 6; + } else if (this->bitFlag == 0x14) { + local_c0 = 0; + } else if (this->bitFlag == 5) { + local_c0 = 2; + } + } else if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 5) == 5) { + local_c0 = 2; + } else { + local_c0 = 2; + } + } else { + local_c0 = 1; + } + } else { + local_c0 = 3; + } + } else if ((this->bitFlag & 2) == 0) { + if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 0x14) == 0x14) { + local_c0 = 0; + } else { + local_c0 = 0; + } + } else { + local_c0 = 7; + } + } else { + local_c0 = 1; + } + } else if ((this->bitFlag & 8) == 0) { + if ((this->bitFlag & 0x80) == 0) { + if ((this->bitFlag & 0x50) == 0x50) { + local_c0 = 6; + } else { + local_c0 = 6; + } + } else { + local_c0 = 5; + } + } else { + local_c0 = 7; + } + } else if ((this->bitFlag & 0x20) == 0) { + if ((this->bitFlag & 2) == 0) { + if ((this->bitFlag & 0x41) == 0x41) { + local_c0 = 4; + } else { + local_c0 = 4; + } + } else { + local_c0 = 3; + } + } else { + local_c0 = 5; + } + if (local_c0 == 0xffffffff) { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x214 + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] & 0x7f; + } else { + uVar12 = (local_c0 - this->mapOrientation) + 8 & 0x80000007; + if ((int)uVar12 < 0) { + uVar12 = (uVar12 - 1 | 0xfffffff8) + 1; + } + this->GfxLayer[this->DAT_SomeTile] + = sVar4 + 0x30c + (short)(uVar12 << 4); + } + } + } + } else { + this->GfxLayer[this->DAT_SomeTile] = sVar4 + 0x2fc; + } + } + LAB_005109e8: + if ((this->LogicLayer[this->DAT_SomeTile] & 0x10000100U) != 0) { + bVar19 = this->DefaultHeightLayer[this->DAT_SomeTile]; + iVar17 = MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::computeClimbRampRotation, this)( + this->DAT_SomeTile, (uint)((int)(iVar17)), + (uint)((int)(this->DAT_SomeY))); + sVar5 = (short)GMTotalPicturesProcessed::instance[9]; + sVar4 = (short)this->field112_0x554908; + if (this->DefaultHeightLayer[this->DAT_SomeTile] < 0x88) { + if (iVar17 == 0) { + if ((this->Logic2Layer[this->DAT_SomeTile] & 2) == 0) { + this->PillarGFXLayer[this->DAT_SomeTile] + = (short)(((((int)(uint)bVar19 >> 3) + -1) * 0x40) / 2) + + (short)GMTotalPicturesProcessed::instance[3] + + (ushort)this->LuminesenceLayer[this->DAT_SomeTile] * 4 + + (this->RandomLayer[this->DAT_SomeTile] & 3); + } else { + this->PillarGFXLayer[this->DAT_SomeTile] = sVar5 + -1 + sVar4; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + } + } else { + this->PillarGFXLayer[this->DAT_SomeTile] = sVar5 + -1 + sVar4; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + } + } else { + this->PillarGFXLayer[this->DAT_SomeTile] = sVar5 + -1 + sVar4; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x800; + } + } + } else { + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] & 0xf7; + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + 4) & 0x100000) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + this->DAT_SomeTile * 4 + -4) & 0x100000) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 4 + + this->DAT_SomeTile * 4) + & 0x100000) + != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + if ((*(uint*)((char*)this->ptr_LogicLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 4 + + this->DAT_SomeTile * 4) + & 0x100000) + != 0) { + this->bitFlag = this->bitFlag | 8; + } + if (this->bitFlag == 0) { + if ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0xc0) == 0) { + bVar19 = 0; + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + 2) + & 0x40) + != 0) { + bVar19 = 0x20; + } + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + -2) + & 0x40) + != 0) { + bVar19 = bVar19 | 2; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x40) != 0) { + bVar19 = bVar19 | 1; + } + if ((*(uint*)((int)puVar18 + 2) & 0x40) != 0) { + bVar19 = bVar19 | 0x40; + } + if ((*puVar18 & 0x40) != 0) { + bVar19 = bVar19 | 0x80; + } + bVar16 = 0; + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + 2) + & 0x80) + != 0) { + bVar16 = 0x20; + } + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + -2) + & 0x80) + != 0) { + bVar16 = bVar16 | 2; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x80) != 0) { + bVar16 = bVar16 | 1; + } + if ((*(uint*)((int)puVar18 + 2) & 0x80) != 0) { + bVar16 = bVar16 | 0x40; + } + if ((*puVar18 & 0x80) != 0) { + bVar16 = bVar16 | 0x80; + } + this->bitFlag = bVar16 & ~bVar19; + if (this->bitFlag != 0) { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xa6] + 0x5c4; + this->PillarGFXLayer[this->DAT_SomeTile] + = (ushort)GMTotalPicturesProcessed::instance[9]; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0xc0; + } + } + if (2 < this->LuminesenceLayer[this->DAT_SomeTile]) { + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xffbf; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] & 0xff7f; + } + local_38 = this->LuminesenceLayer[this->DAT_SomeTile] - 2; + if (local_38 < 0) { + local_38 = 0; + } + sVar4 = (short)local_38; + if ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0xc0) == 0) { + if ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0x100) == 0) { + this->bitFlag = 0; + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + + 2) + & 0x100) + != 0) { + this->bitFlag = 0x20; + } + if ((*(uint*)((char*)this->ptr_MiscDisplayLayer + this->DAT_SomeTile * 2 + + -2) + & 0x100) + != 0) { + this->bitFlag = this->bitFlag | 2; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x100) != 0) { + this->bitFlag = this->bitFlag | 1; + } + if ((*(uint*)((int)puVar18 + 2) & 0x100) != 0) { + this->bitFlag = this->bitFlag | 0x40; + } + if ((*puVar18 & 0x100) != 0) { + this->bitFlag = this->bitFlag | 0x80; + } + puVar18 = (uint*)((char*)this->ptr_MiscDisplayLayer + + *(int*)((int)((char*)this->ptr_MovementDirectionTranslationMatrix + + this->DAT_SomeY * 0x20) + + 0x10) + * 2 + + this->DAT_SomeTile * 2); + if ((*(uint*)((int)puVar18 + -2) & 0x100) != 0) { + this->bitFlag = this->bitFlag | 4; + } + if ((*(uint*)((int)puVar18 + 2) & 0x100) != 0) { + this->bitFlag = this->bitFlag | 0x10; + } + if ((*puVar18 & 0x100) != 0) { + this->bitFlag = this->bitFlag | 8; + } + if (this->bitFlag != 0) { + local_ac = 2; + uVar12 = (uint)this->bitFlag + << ((byte)this->mapOrientation & 0x1f); + uVar12 = uVar12 & 0xff | (int)uVar12 >> 8; + switch (uVar12) { + case 1: + local_b0 = 0x1c; + break; + case 2: + case 3: + case 6: + case 7: + local_b0 = 0xc; + local_ac = 4; + break; + case 4: + local_b0 = 0x1a; + break; + default: + local_b4 = 0; + for (local_b8 = 0; local_b8 < 8; local_b8 = local_b8 + 1) { + if ((1 << ((byte)local_b8 & 0x1f) & uVar12) != 0) { + local_b4 = local_b4 + 1; + } + } + if (local_b4 < 4) { + local_b0 = 0x20; + } else { + local_b0 = 0x21; + } + local_ac = 1; + break; + case 8: + case 0xc: + case 0x18: + case 0x1c: + local_b0 = 8; + local_ac = 4; + break; + case 0xe: + case 0xf: + case 0x1e: + case 0x1f: + local_b0 = 0x16; + break; + case 0x10: + local_b0 = 0x18; + break; + case 0x20: + case 0x30: + case 0x60: + case 0x70: + local_b0 = 4; + local_ac = 4; + break; + case 0x38: + case 0x3c: + case 0x78: + case 0x7c: + local_b0 = 0x14; + break; + case 0x40: + local_b0 = 0x1e; + break; + case 0x80: + case 0x81: + case 0xc0: + case 0xc1: + local_b0 = 0; + local_ac = 4; + break; + case 0x83: + case 0x87: + case 0xc3: + case 199: + local_b0 = 0x10; + break; + case 0xe0: + case 0xe1: + case 0xf0: + case 0xf1: + local_b0 = 0x12; + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xa6] + + (short)((int)(short)this->RandomLayer[this->DAT_SomeTile] + % local_ac) + + local_b0 + 8 + sVar4 * 0xf6; + this->MiscDisplayLayer[this->DAT_SomeTile] + = this->MiscDisplayLayer[this->DAT_SomeTile] | 0x200; + } + } else { + local_94 = 2; + uVar15 = (int)this->CertainPathLayer[this->DAT_SomeTile] & 0xff; + uVar12 = uVar15 << ((byte)this->mapOrientation & 0x1f); + uVar12 = uVar12 & 0xff | (int)uVar12 >> 8; + switch (uVar12) { + case 1: + local_9c = 0x1c; + break; + case 2: + case 3: + case 6: + case 7: + local_9c = 0xc; + local_94 = 4; + break; + case 4: + local_9c = 0x1a; + break; + default: + local_a0 = 0; + for (local_a4 = 0; local_a4 < 8; local_a4 = local_a4 + 1) { + if ((1 << ((byte)local_a4 & 0x1f) & uVar12) != 0) { + local_a0 = local_a0 + 1; + } + } + if (local_a0 < 4) { + local_9c = 0x20; + } else { + local_9c = 0x21; + } + local_94 = 1; + break; + case 8: + case 0xc: + case 0x18: + case 0x1c: + local_9c = 8; + local_94 = 4; + break; + case 0xe: + case 0xf: + case 0x1e: + case 0x1f: + local_9c = 0x16; + break; + case 0x10: + local_9c = 0x18; + break; + case 0x20: + case 0x30: + case 0x60: + case 0x70: + local_9c = 4; + local_94 = 4; + break; + case 0x38: + case 0x3c: + case 0x78: + case 0x7c: + local_9c = 0x14; + break; + case 0x40: + local_9c = 0x1e; + break; + case 0x80: + case 0x81: + case 0xc0: + case 0xc1: + local_9c = 0; + local_94 = 4; + break; + case 0x83: + case 0x87: + case 0xc3: + case 199: + local_9c = 0x10; + break; + case 0xe0: + case 0xe1: + case 0xf0: + case 0xf1: + local_9c = 0x12; + } + local_9c = (short)((int)(short)this->RandomLayer[this->DAT_SomeTile] + % local_94) + + local_9c; + if (uVar15 + != ((int)this->CertainPathLayer[this->DAT_SomeTile] >> 8 + & 0xffU)) { + local_9c = local_9c + 0x66; + } + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[0xa6] + local_9c + + 0x2a + sVar4 * 0xf6; + } + } + if ((this->MiscDisplayLayer[this->DAT_SomeTile] & 0x3c0) == 0) { + this->GfxLayer[this->DAT_SomeTile] + = (this->RandomLayer[this->DAT_SomeTile] & 7) + + (short)GMTotalPicturesProcessed::instance[0xa6] + sVar4 * 0xf6; + this->PillarGFXLayer[this->DAT_SomeTile] + = (ushort)GMTotalPicturesProcessed::instance[9]; + } + } else { + this->GfxLayer[this->DAT_SomeTile] + = (short)GMTotalPicturesProcessed::instance[5] + 0x2fc; + this->Logic2Layer[this->DAT_SomeTile] + = this->Logic2Layer[this->DAT_SomeTile] | 8; + } + } + } + LAB_0050c199: + this->DAT_SomeX = this->DAT_SomeX + 1; + } + } + } + } + } + } + return; + } + +} +} + +#pragma optimize("", on) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 82f62dece..c5c8c6926 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42767,7 +42767,7 @@ SHC_3BB0A8C1_0x00508DD0 | 43.1% | extra callee-saved reg SHC_3BB0A8C1_0x00508EC0 | 27.5% | 35.40% spill order regalloc -SHC_3BB0A8C1_0x00509180 | 0.0% | Pending +SHC_3BB0A8C1_0x00509180 | 15.7% | 15.65% repaired, arms restored SHC_3BB0A8C1_0x0050A74E | 0.0% | Pending From 402281a505ff8c6dd9cc4ca894e9f9700f79e0a0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 6 Oct 2026 00:54:11 +0200 Subject: [PATCH 202/252] reimplement: SHC_3BB0A8C1_0x00506370 53.19% signed % and / restored --- IMPLEMENTATION_CHEAT_SHEET.md | 141 ++++++++++ reccmp/dll/requirements.txt | 2 +- .../updateBuildingGraphicsLayer.cpp | 244 +++++++++++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- tools/mcp/openshcmcp.py | 2 +- .../Get-Incomplete-Status-On-Branch.ps1 | 1 + .../Promote-Branch-To-Worktree.ps1 | 36 +++ ...urces-From-Incomplete-Status-On-Branch.ps1 | 43 +++ tools/reimplementation-helper/batch/README.md | 72 +++++- .../batch/build_quiet.py | 29 ++- tools/reimplementation-helper/batch/common.py | 21 ++ tools/reimplementation-helper/batch/decast.py | 96 +++++++ .../batch/declare_at_use.py | 101 ++++++++ .../reimplementation-helper/batch/deparen.py | 170 ++++++++++++ .../reimplementation-helper/batch/diff_jcc.py | 84 ++++++ .../batch/diff_slots.py | 41 +++ .../batch/diff_triage.py | 97 +++++++ .../batch/diff_types.py | 140 ++++++++++ .../reimplementation-helper/batch/orig_asm.py | 137 ++++++++++ .../batch/quick_diff.py | 167 ++++++++++++ .../batch/rank_functions.py | 33 +++ .../batch/reccmp_report.py | 19 ++ .../batch/reorder_search.py | 204 +++++++++++++++ .../batch/scan_chains.py | 48 ++++ .../batch/scan_dispatch.py | 39 +++ .../batch/strip_noise_comments.py | 107 ++++++++ .../batch/test_deparen.py | 47 ++++ .../batch/test_undiv.py | 45 ++++ .../batch/test_unmod.py | 60 +++++ .../batch/test_unptr.py | 70 +++++ .../batch/try_styles.py | 121 +++++++++ tools/reimplementation-helper/batch/undiv.py | 150 +++++++++++ tools/reimplementation-helper/batch/unmod.py | 92 +++++++ tools/reimplementation-helper/batch/unptr.py | 80 ++++++ .../set_sources_from_incomplete_status.py | 77 ++++++ 35 files changed, 2749 insertions(+), 69 deletions(-) create mode 100644 tools/reimplementation-helper/Get-Incomplete-Status-On-Branch.ps1 create mode 100644 tools/reimplementation-helper/Promote-Branch-To-Worktree.ps1 create mode 100644 tools/reimplementation-helper/Set-Sources-From-Incomplete-Status-On-Branch.ps1 create mode 100644 tools/reimplementation-helper/batch/decast.py create mode 100644 tools/reimplementation-helper/batch/declare_at_use.py create mode 100644 tools/reimplementation-helper/batch/deparen.py create mode 100644 tools/reimplementation-helper/batch/diff_jcc.py create mode 100644 tools/reimplementation-helper/batch/diff_slots.py create mode 100644 tools/reimplementation-helper/batch/diff_triage.py create mode 100644 tools/reimplementation-helper/batch/diff_types.py create mode 100644 tools/reimplementation-helper/batch/orig_asm.py create mode 100644 tools/reimplementation-helper/batch/quick_diff.py create mode 100644 tools/reimplementation-helper/batch/rank_functions.py create mode 100644 tools/reimplementation-helper/batch/reorder_search.py create mode 100644 tools/reimplementation-helper/batch/scan_chains.py create mode 100644 tools/reimplementation-helper/batch/scan_dispatch.py create mode 100644 tools/reimplementation-helper/batch/strip_noise_comments.py create mode 100644 tools/reimplementation-helper/batch/test_deparen.py create mode 100644 tools/reimplementation-helper/batch/test_undiv.py create mode 100644 tools/reimplementation-helper/batch/test_unmod.py create mode 100644 tools/reimplementation-helper/batch/test_unptr.py create mode 100644 tools/reimplementation-helper/batch/try_styles.py create mode 100644 tools/reimplementation-helper/batch/undiv.py create mode 100644 tools/reimplementation-helper/batch/unmod.py create mode 100644 tools/reimplementation-helper/batch/unptr.py create mode 100644 tools/reimplementation-helper/set_sources_from_incomplete_status.py diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index 0b7151e3b..2ac9a43ed 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -50,6 +50,34 @@ This also applies when putting instructions inside the condition branches. Naturally, the logic flow needs to be kept, so the update of a variable can not move before or after another usage of the same variable. +### Statement Order + +The order of instructions in the assembly is not the order of the statements in the original source. +Within a boundary the compiler schedules freely, so do not copy the instruction order into the source. + +This matters most for long runs of independent stores into one object, as in `AICState::setAICParameters_NN`: +the whole body is `this->aics[aicIndex]. = ;` over ~130 fields, and the compiler emits +those `mov dword ptr [eax + ], ` instructions in an order of its own. Rewriting all 16 of +those functions so their statements followed the original's store order made every one of them *worse* +(e.g. `setAICParameters_14` 82.4% -> 50.0%). + +That does not make the order unrecoverable. The compiler moves only the stores whose value sits in a **register**: +when a constant's register is about to be reloaded with another constant, the stores still waiting for the old value +are pulled up in front of the reload, and stores of a newly loaded constant are gathered behind it. Stores of an +**immediate** (`mov dword ptr [eax + off], 0x46`) stay where the source put them. So: + +1. Take the immediate stores of the original as the skeleton of the source order. Across a family of sibling + functions the skeleton is the same template, so vote the precedence of every pair of fields over all siblings - + a field that is a register store in one function is an immediate in another. +2. Put each register store back at its place in that template (mostly struct order, with the template's own local + swaps: `unknown002` before `unknown001`, `populationPerFarm` before `unknown011`, `recruitProbDefWeak` before + `recruitProbDefDefault`, `RecruitIntervalWeak` before `RecruitInterval`, `AttMaxAssassins` before `AttUnit2`). +3. Compile and move the few statements that still sit elsewhere next to their neighbour in the original. + +All 16 `setAICParameters_NN` went from 75-95% to 100% this way, with no type or header change; the earlier attempt +failed because it copied the *instruction* order, hoisted stores included. Which constant lands in which register +then follows by itself - it was a consequence of the statement order, not of register pressure. + ## Structure ### Bitwise Operations @@ -99,6 +127,56 @@ SEC_RNG::ptr->currentNumber1 % 4 - The assembly may contain multiple assigns of the same value to the same variable within the same boundary. This might be optimization suggesting there was only one assign. - The decompiler may suggest multiple assigns of the same value to the same variable within the same boundary. If this is not present in the assembly, it might be an artifact. - If a variable is stored in a temporary, before it is directly being incremented or decremented by one, suggests a post-increment/decrement, even more if the temporary is used after this. +- Do not hoist a repeated sub-expression into a local just because it appears several times. `int const halfWidth = barWidth / 2;` + used at four call sites lost against the original, which recomputes `barWidth / 2` at every use (SHC_3BB0A8C1_0x004B20B0, 67.6% -> 82.4%). + Write the expression out again at each use and let the compiler decide. +- **A local that only copies a field lets the compiler fold what the original kept separate.** MSVC forward-substitutes + an expression built from a register value (`int aiType = pd.aiType; ... int aicIndex = aiType - 1;`) into its use, so + `aics[aicIndex].x` becomes `[reg*0x2a4 + this + (off - 0x2a4)]` with no decrement left. It does **not** substitute + an expression that contains a memory read across a store, a call or a branch. The original's + `test eax, eax; je; add eax, -1; imul eax, eax, 0x2a4; ... [eax + ecx + off]` therefore needs the field tested + directly and read again for the index: + ```cpp + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AIT_NULL) + return FALSE; + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + ``` + `determineAIPlayerHelp`, `determineAIPlayerAttackRequestResponse`, `addUnitToSmallestPatrolTribe`, + `setCurrentAttackStrength` all went to 100% on this alone. Fifteen other spellings of the index (casts, pointer + arithmetic, an inlined accessor, in-place decrement, unsigned) all folded - only the missing local matters. The + same applies to any other decompiler local for a field (`tracker`, `outerPatrolGroupsCount`): reading the field at + every use took `getTargetableBuildingForPlayerID` from 65% to 100%. +- **A constant index held in a local stops the per-struct multiply being shared.** When the original recomputes + `playerID * 0x39f4` in every basic block (`mov eax, ecx; imul eax, eax, 0x39f4` three times, with `playerID` staying + in its register) while we multiply once, the array index in the source was a *variable* that the optimizer only + later found to be constant. With a variable index MSVC factors each access by its own element size + (`playerID * 0x1cfa` for a `short` array, `* 0xe7d` for an `int` array), so the three accesses are three different + expressions and nothing is common. Write `int tribeIndex = 11;` and index with it: + ```cpp + int tribeIndex = 11; + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + return; + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex]; + ``` + Eight `AI::AICState` tribe-command functions went from 38-62% to 100% (`setTribe0xbToAggressiveAndAttack`, + `sendTribeToAttack`, `aiCommandTribe11/13`, ...). The same happens when the index is a field the code has just + compared against a constant: `pd.aivCurrentPauseIndex == 1 && pd.aivPauses[pd.aivCurrentPauseIndex] > 0`, not + `aivPauses[1]`. It is not universal - on functions whose index is a loop sum (`aiTribeIDs[166 + i]`) the local made + things worse. +- A constant kept in a callee-saved register from the top of the function (`mov ebx, 1` before the first branch, later + `mov [field], ebx`) is a **result variable** initialised at the top and stored once at the end, not two literal + stores: `int isNotNervous = 1; ... if (cond) isNotNervous = 0; else {...} field = isNotNervous;` + (`computeNervousness` 77% -> 100%). +- `add reg, -N` where we emit `sub reg, N` or `cmp reg, N` means two constants were merged: the source compared a + derived value, `aicIndex == 7` with `aicIndex = aiType - 1`, not `aiType == 8` + (`removeOrganismsAndSetMoveDestinationPairs` 97.9% -> 100%). +- Where two arguments are loaded on either side of a store (`mov ecx, [x]` ... `mov [stance], 1` ... `mov eax, [y]`), + give each a local and put the statements in that order: `int x = pd.someX; tribe.unitStance = ...; int y = pd.someY;` + (`makeUnitsGoDefensiveAndBackToSomeLocation` 95.7% -> 100%). Without a store in between, the *declaration order* + of two such locals picks which one gets `ecx` (`sendUnitsToAttackBreachedCastle` 98.7% -> 100%). +- The opposite does happen for the operands of a single statement: in `SHC_3BB0A8C1_0x00522520` the original evaluates + `unitID / 16` and `unitID % 16` into locals before the compound assignment. If a `|=`/`&=` statement with computed index + and mask does not match, give the index and the mask a local each and keep the declaration order the assembly shows. ### Conditionals @@ -110,6 +188,14 @@ SEC_RNG::ptr->currentNumber1 % 4 - If a condition suddenly uses a normally signed variable as unsigned value (e.g. `ja` compared to signed `jg`) and most times also contains a subtraction, it suggests a range condition optimization. The actual value was moved to 0 to allow expressing this via a single check: - Decomp code example: `DAT_GameCore.missionNumber1to20 - 1U < 0x14` - Original (likely): `1 <= DAT_GameCore.missionNumber1to20 && DAT_GameCore.missionNumber1to20 <= 20` +- A two-sided range check that is the whole body of a `BOOL`-returning function is compiled branchless. Write it as one + expression, `return lo <= value && value <= hi;`, not as nested `if`s with early returns, and use the literals the + assembly shows rather than a `short`/`ushort` local holding the field (SHC_3BB0A8C1_0x00530FD0, 78.3% -> 100%). +- Which form a boolean result takes is **not** predictable and has to be tried both ways. The folded + `return (x & MASK) == VALUE;` matched at only 40% for SHC_3BB0A8C1_0x004549C0; spelling it out as + `if ((x & MASK) == VALUE) { return TRUE; } else { return FALSE; }`, with locals for the computed index and the loaded + byte, reached 100%. Together with the range-check case above this means: folded expression and explicit + `TRUE`/`FALSE` branches are two separate candidates, measure both. - A switch with fewer then 4 cases is often simplified and uses subtractions in assembly to compare the value: ``` MOV EAX,[DAT_SoundEffectsHelperData1.SEC_Section1079. volumeLevel] @@ -196,6 +282,48 @@ 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. +A global used as a running counter alongside the loop index is usually incremented inside the loop, even when its final +value is a constant. Ghidra shows the folded result: `DAT_CurrentUnitSlotID = 2500;` placed around the loop is really +`DAT_CurrentUnitSlotID = 1;` before it and `DAT_CurrentUnitSlotID += 1;` as the first statement of the body. This was +worth the last 8-10% on the whole `Map::Version::UpgradeMapUnitsTo_*` family (0x0053B310, 0x0053B530, 0x0053B570, +0x0053B5E0 all 90% -> 100%). + +`!=` as the loop bound suppresses MSVC's unrolling. If the original ends the loop with `jne` while we emit `jl` and an +unrolled body, write `for (int i = 1; i != 2500; ++i)` instead of `i < 2500` (SHC_3BB0A8C1_0x0053B340, 53% -> 91%). + +- A loop whose early exit returns the same value as the code after the loop was a `break`, not a `return`. The tell is + callee-saved registers pushed *after* the loop's entry test and one shared `mov eax, result` behind the loop, where + an early `return result;` makes us push everything in the prologue (`assignRequiredIdleEngineersToNewTribe`, + `addEngineersToSelection`, both ~88% -> 100%). +- Do not add a guard the loop condition already expresses. `if (id == 0) return 0;` in front of + `for (; id != 0; id = next(id))` moved one `push` across a branch; without it the compiler derives the same early + exit itself and places it where the original does (`aiRequiresExtraOxtethers`). Likewise put the block the + original keeps inline first: `if (best > 20) { store; return 1; } return 0;` rather than the inverted guard. + +- **Several exits that end in the same statement were usually one statement.** MSVC copies a short shared tail + (a store or a call followed by the epilogue) into each predecessor, so three `mov word ptr [tribe.unitStance], 2` + + `ret` blocks in the original do not mean three assignments in the source. Writing the assignment once after an + `if / else if` ladder instead of `stance = X; return;` in every arm changes how often each value is *used*, and the + use count is what ranks values for the callee-saved registers - so this is the fix when a function matches + instruction for instruction except that two registers are swapped (`tribeID` in `ebx` and the tribe offset in `ebp` + on one side, the reverse on the other). `giveMoveCommandToSortieUnits` 79.6% -> 100%, `instructTribe166ToMove` + 81.8% -> 100%, `assignUnitToATribe` 86.1% -> 100% (one `addUnitToTribe(unitID, tribeID)` after the branches + instead of three calls). When one of the arms must skip a call the others share, a `bool` set in the arms and + tested once afterwards compiles away and gives the single call site the original has. +- A search loop whose "found a free slot" exit must skip the check that follows the loop has its end test **inside + the body**: `for (;; i++) { if (i >= count) { if (best == 0) return 0; break; } ... if (free) { best = create(); + bestIndex = i; break; } ... }`. A `for (i < count)` loop with the check after it tests `best` on both paths, and + duplicating the tail into the create path changes the frame. With the test in the body the compiler rotates it to + the bottom and lays the blocks out as the original does (`getSmallestPatrolTribe` 65.2% -> 100%). The same + function needed `int i = 0;` declared *first*, before the other zero-initialised locals, to get the original's + `xor` order - declaration order did not matter anywhere else it was tried. + +- `mov edx, esi; add esi, 1` at the **top** of a loop body, with the body then indexing by the copy, is a `while` + loop that takes the index and advances the counter first: `while (i < count) { int index = i; i++; if (...[index]...) + { ...; return; } }`. A `for (...; i++)` with the same body does not produce it. Together with `int i = 0;` + declared where the original's `xor esi, esi` sits (here before an earlier early-return test, which then compares + against that zero register) this took `generateSiegeCreationInformation` from 39.4% to 100%. + ### GOTO A function may contain multiple GOTOs. @@ -230,6 +358,19 @@ It is hard to find these cases. I one situation, local variables that were used ## Functions +### Return Values + +A function declared `void` whose assembly still leaves a value in EAX at the return usually returns it. The most common +case is a function that returns the ID it was passed: changing `void EntityState::activateProjectileEntity(int entityID)` +to `int` with a trailing `return entityID;` took SHC_3BB0A8C1_0x004039B0 from 36.4% to 100%. Fix the signature in the +generated header rather than working around the difference. + +### Link-Time Code Generation + +A volatile register (usually ECX or EDX) that stays live across a call in the original, without being reloaded, means +that call was compiled with LTCG. This is fixable, not a permanent blocker: add the `.cpp` to `cmake/compiler-flags-gl.txt` +so it is built with `/GL`. SHC_3BB0A8C1_0x00504EE0 went from 38.5% to 100% and SHC_3BB0A8C1_0x0045B7F0 to 100% that way. + ### Parameters Parameters might not be pushed like normal in certain cases. diff --git a/reccmp/dll/requirements.txt b/reccmp/dll/requirements.txt index fc16b93e6..f8eaa3e13 100644 --- a/reccmp/dll/requirements.txt +++ b/reccmp/dll/requirements.txt @@ -1 +1 @@ -git+https://github.com/isledecomp/reccmp \ No newline at end of file +git+https://github.com/sourcehold/reccmp diff --git a/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp b/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp index e326669ea..c6ec17988 100644 --- a/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp +++ b/src/OpenSHC/Map/TileMapState/updateBuildingGraphicsLayer.cpp @@ -38,82 +38,134 @@ namespace Map { if (this->refreshRelatedOne == 0 && DAT_BuildingsState::instance.buildings[buildingID].gfxOffset != 0) { DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 = 1; } - int stored = DAT_BuildingsState::instance.buildings[buildingID].currentNumberOfResource - (int)DAT_BuildingsState::instance.buildings[buildingID].someResourceNumber; + int stored = DAT_BuildingsState::instance.buildings[buildingID].currentNumberOfResource + - (int)DAT_BuildingsState::instance.buildings[buildingID].someResourceNumber; int index = 0; do { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getBuildingSizeIndexMappingData, this)( index, DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight); - int tile = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + (short)buildingYPos].addXgetTile + int tile + = DAT_ViewportRenderState::instance.translationMatrix[this->buildingY + (short)buildingYPos].addXgetTile + (short)buildingXPos + this->buildingX; if (this->field93_0x5548c8 != 0) { /* the placement overlay replaces every building graphic with its outline */ this->AlphaGFXLayer[tile] = 0; - this->GfxLayer[tile] = ((short)DAT_TerrainDefinedData::instance.BrushSizeArray[DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight + 7] + (short)this->buildingRotationRelatedValue - + (short)GMTotalPicturesProcessed::instance[0x9d]) + this->GfxLayer[tile] + = ((short)DAT_TerrainDefinedData::instance + .BrushSizeArray[DAT_BuildingsState::instance.buildings[buildingID].widthOrHeight + 7] + + (short)this->buildingRotationRelatedValue + (short)GMTotalPicturesProcessed::instance[0x9d]) - 1; - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_STOCKPILE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_QUARRYSTOCKPILE) { + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_STOCKPILE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_QUARRYSTOCKPILE) { /* a stockpile's pile grows with what is stored on it */ if (stored < 1) { - this->GfxLayer[tile] = (short)this->buildingRotationRelatedValue + (short)GMTotalPicturesProcessed::instance[0xf] + 4; + this->GfxLayer[tile] = (short)this->buildingRotationRelatedValue + + (short)GMTotalPicturesProcessed::instance[0xf] + 4; } else { short resource = DAT_BuildingsState::instance.buildings[buildingID].currentStoredResourceType; short pile; if (DAT_TerrainDefinedData::instance.field1001_0x8b4[resource] == 2) { - int remaining = DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource - stored; + int remaining + = DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource - stored; pile = (short)this->buildingRotationRelatedValue - + ((short)((remaining + (remaining >> 0x1f & 3U)) >> 2) + ((ushort)remaining & 3) * 0xc) - * 4; + + ((short)(remaining / 4) + ((ushort)remaining & 3) * 0xc) * 4; } else if (DAT_TerrainDefinedData::instance.field1001_0x8b4[resource] == 0) { pile = (short)this->buildingRotationRelatedValue + -4 + (short)stored * 4; } else { - pile = (short)this->buildingRotationRelatedValue + ((short)DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource - (short)stored) * 4; + pile = (short)this->buildingRotationRelatedValue + + ((short)DAT_BuildingsState::instance.buildings[buildingID].currentLimitOfResource + - (short)stored) + * 4; } - this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[0xf] + (short)DAT_TerrainDefinedData::instance.field996_0x84c[resource] + -1 + pile; + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[0xf] + + (short)DAT_TerrainDefinedData::instance.field996_0x84c[resource] + -1 + pile; } - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_MERCENARYPOST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_BARRACKS - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_OUTPOST_EUROPEAN) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR_LEFT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR_RIGHT) { + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_MERCENARYPOST + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_BARRACKS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_OUTPOST_EUROPEAN) { + this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue) + - 1; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_KEEPDOOR_LEFT + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_KEEPDOOR_RIGHT) { /* a side door faces along the keep's axis, so its graphic follows the map rotation */ uint facing = this->mapOrientation; - if (DAT_BuildingsState::instance.buildings[buildingID].orientation == 6 || DAT_BuildingsState::instance.buildings[buildingID].orientation == 2) { - facing = this->mapOrientation + 2U & 0x80000007; - if ((int)facing < 0) { - facing = (facing - 1 | 0xfffffff8) + 1; - } + if (DAT_BuildingsState::instance.buildings[buildingID].orientation == 6 + || DAT_BuildingsState::instance.buildings[buildingID].orientation == 2) { + facing = (this->mapOrientation + 2) % 8; } if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { if (facing == 2 || facing == 6) { this->GfxLayer[tile] - = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; + = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; } else { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated - + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) - 1; } } else if (facing == 2 || facing == 6) { - this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset; + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset; } else { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + - 1; } - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_KEEPDOOR) { + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_KEEPDOOR) { if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { if (this->mapOrientation != 2 && this->mapOrientation != 6) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated - + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID) - 1; } else { this->GfxLayer[tile] - = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; + = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID; } } else { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated - + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) - 1; } - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_WOODGATE1) { + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_GATEHOUSELARGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_GATEHOUSESMALL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_WOODGATE1) { int variation; if (this->mapOrientation == 2 || this->mapOrientation == 6) { variation = (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0x50) + 0x50; @@ -122,67 +174,131 @@ namespace Map { } if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 == 0) { if (variation == 0x50) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue) + - 1; } else { this->GfxLayer[tile] - = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset2) + (short)this->buildingRotationRelatedValue) - 1; + = (((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset2) + + (short)this->buildingRotationRelatedValue) + - 1; } } else if (variation != 0x50) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset3 + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset3 + + (short)this->buildingRotationRelatedValue) + - 1; } else { - this->GfxLayer[tile] = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = (((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + + (short)this->buildingRotationRelatedValue) + - 1; } - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_MANORHOUSE) { + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_MANORHOUSE) { int variation = 0x50; if (this->mapOrientation == 2 || this->mapOrientation == 6) { variation = 0x51; } if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 != 0) { if (variation == 0x50) { - this->GfxLayer[tile] = (((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = (((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset) + + (short)this->buildingRotationRelatedValue) + - 1; } else { - this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)this->buildingRotationRelatedValue + 0x298; + this->GfxLayer[tile] + = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)this->buildingRotationRelatedValue + 0x298; } } else if (variation == 0x50) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue) + - 1; } else { - this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)this->buildingRotationRelatedValue + 0x236; + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)this->buildingRotationRelatedValue + 0x236; } - } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { - int plank = DAT_TerrainDefinedData::instance.field2467_0x1fec[(int)DAT_BuildingsState::instance.buildings[buildingID].buildingVariation / 2][index]; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == OpenSHC::Map::Buildings::BT_DRAWBRIDGE) { + int plank + = DAT_TerrainDefinedData::instance + .field2467_0x1fec[(int)DAT_BuildingsState::instance.buildings[buildingID].buildingVariation + / 2][index]; if (plank != 0) { - this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)plank + 0x61e; - } else if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(tile) - == 0) { + this->GfxLayer[tile] = (short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)plank + 0x61e; + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::returnOwnedMoatAtTile, this)(tile) == 0) { this->GfxLayer[tile] = ((byte)this->RandomLayer[tile] & 3) + (ushort)this->LuminesenceLayer[tile] * 4 + (short)GMTotalPicturesProcessed::instance[2]; } else { this->GfxLayer[tile] = ((byte)this->RandomLayer[tile] & 3) + (this->LuminesenceLayer[tile] + 0x33) * 4 + (short)GMTotalPicturesProcessed::instance[5]; } - } else if ((DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_KILLINGPIT || DAT_BuildingsState::instance.buildings[buildingID].state > 0 - || DAT_GameState::instance.mapAndTime.playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner] + } else if ((DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_KILLINGPIT + || DAT_BuildingsState::instance.buildings[buildingID].state > 0 + || DAT_GameState::instance.mapAndTime + .playerTeams[DAT_BuildingsState::instance.buildings[buildingID].owner] == DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] || DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_EDITOR) - && DAT_BuildingsState::instance.buildings[buildingID].buildingType != OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { + && DAT_BuildingsState::instance.buildings[buildingID].buildingType + != OpenSHC::Map::Buildings::BT_SIEGETOWER_PLACED) { /* a killing pit is invisible to anyone not on the owner's team */ if (DAT_BuildingsState::instance.buildings[buildingID].buildingVariation == 0xf) { if (DAT_BuildingsState::instance.buildings[buildingID].field62_0xb0 != 0) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset + (short)this->buildingRotationRelatedValue) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].gfxOffset + + (short)this->buildingRotationRelatedValue) + - 1; } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingIsVisuallyActive == 0) { - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated - + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue) - 1; } else { this->GfxLayer[tile] - = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].visuallyActiveSpriteID + (short)this->buildingRotationRelatedValue) - 1; + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].visuallyActiveSpriteID + + (short)this->buildingRotationRelatedValue) + - 1; } - this->AlphaGFXLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].unknownManorHouseOrStoneKeepRelated - + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue) + this->AlphaGFXLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID] + .unknownManorHouseOrStoneKeepRelated + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue) - 1; } else { - int relative = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation - this->mapOrientation; + int relative + = DAT_BuildingsState::instance.buildings[buildingID].buildingVariation - this->mapOrientation; if (relative < 0) { relative = relative + 8; } @@ -201,9 +317,17 @@ namespace Map { } else { sprite = (short)DAT_BuildingsState::instance.buildings[buildingID].visuallyActiveSpriteID; } - this->GfxLayer[tile] = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + sprite + (short)this->buildingRotationRelatedValue + span * rotation) - 1; + this->GfxLayer[tile] + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + sprite + (short)this->buildingRotationRelatedValue + span * rotation) + - 1; this->AlphaGFXLayer[tile] - = ((short)GMTotalPicturesProcessed::instance[(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + (short)this->buildingRotationRelatedValue + span * rotation) - 1; + = ((short)GMTotalPicturesProcessed::instance + [(short)DAT_BuildingsState::instance.buildings[buildingID].spriteSheetID] + + (short)DAT_BuildingsState::instance.buildings[buildingID].spriteID + + (short)this->buildingRotationRelatedValue + span * rotation) + - 1; } } index++; diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c5c8c6926..8524df435 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -42081,7 +42081,7 @@ SHC_3BB0A8C1_0x00505A10 | 0.0% | Pending SHC_3BB0A8C1_0x005060C0 | 0.0% | Pending -SHC_3BB0A8C1_0x00506370 | 42.1% | 44.49% per-arm stores vs share +SHC_3BB0A8C1_0x00506370 | 53.2% | signed % and / restored SHC_3BB0A8C1_0x00506AD0 | 77.9% | buildingType chain tail-merge diff --git a/tools/mcp/openshcmcp.py b/tools/mcp/openshcmcp.py index af461afec..1d380060c 100644 --- a/tools/mcp/openshcmcp.py +++ b/tools/mcp/openshcmcp.py @@ -111,7 +111,7 @@ def extract_multiple_functions_assembly_diffs(function_names: List[str], match_p Returns: Tuple of (success, diffs of the functions, stdout, stderr) """ - cmd = [str(cwd / "reccmp" / "dll" / "run.bat"), "reccmp-reccmp", "--target", "STRONGHOLDCRUSADER", "--json", "diff.json"] + cmd = [str(cwd / "reccmp" / "dll" / "run.bat"), "reccmp-reccmp", "--target", "STRONGHOLDCRUSADER", "--json", "diff.json", "--resolve-wrapped-calls"] try: result = subprocess.run( diff --git a/tools/reimplementation-helper/Get-Incomplete-Status-On-Branch.ps1 b/tools/reimplementation-helper/Get-Incomplete-Status-On-Branch.ps1 new file mode 100644 index 000000000..acab58515 --- /dev/null +++ b/tools/reimplementation-helper/Get-Incomplete-Status-On-Branch.ps1 @@ -0,0 +1 @@ +git diff main HEAD .\status\addresses-SHC-3BB0A8C1.txt | Where-Object {$_.StartsWith("+SHC") -and (-not $_.Contains("| 100"))} | ForEach-Object {$_.SubString(1)} diff --git a/tools/reimplementation-helper/Promote-Branch-To-Worktree.ps1 b/tools/reimplementation-helper/Promote-Branch-To-Worktree.ps1 new file mode 100644 index 000000000..8a188a9b1 --- /dev/null +++ b/tools/reimplementation-helper/Promote-Branch-To-Worktree.ps1 @@ -0,0 +1,36 @@ +param ( + [string]$Branch, + [string]$Path +) + +$ErrorActionPreference = "Stop" + +$CurrentBranch = git branch --show-current + +if ("main" -ne "$CurrentBranch") {Write-Error "Not on 'main'"} + +mkdir "$Path" + +git branch $Branch + +git worktree add "$Path" $Branch + +mkdir "$Path\_original" + +copy "_original\Stronghold Crusader.exe" "$Path\_original\" + +pushd "$Path" + +git submodule update --init --recursive + +reccmp\dll\setup.bat + +git push --set-upstream origin $Branch + +.\tools\reimplementation-control\Enable-Reimplemented-Data.ps1 + +.\build.bat RelWithDebInfo OpenSHC.dll + +reccmp/dll/run.bat reccmp-reccmp --target STRONGHOLDCRUSADER + +popd diff --git a/tools/reimplementation-helper/Set-Sources-From-Incomplete-Status-On-Branch.ps1 b/tools/reimplementation-helper/Set-Sources-From-Incomplete-Status-On-Branch.ps1 new file mode 100644 index 000000000..655754193 --- /dev/null +++ b/tools/reimplementation-helper/Set-Sources-From-Incomplete-Status-On-Branch.ps1 @@ -0,0 +1,43 @@ +# Writes the .cpp files of every function this branch touched but did not finish (status neither +# 100% nor 0.0%) to cmake/openshc-sources.txt.local. Run from the repository root. +param( + [string]$Base = "main", + [string]$StatusFile = "status/addresses-SHC-3BB0A8C1.txt", + [string]$SourceRoot = "src/OpenSHC", + [string]$Destination = "cmake/openshc-sources.txt.local" +) + +$lines = git diff $Base HEAD -- $StatusFile | Where-Object { $_.StartsWith("+SHC") -and (-not $_.Contains("| 100")) -and (-not $_.Contains("| 0.0%")) } | ForEach-Object { $_.SubString(1) } + +# address -> status line +$wanted = @{} +foreach ($line in $lines) { + if ($line -match "^SHC_[0-9A-Fa-f]+_0x([0-9A-Fa-f]+)") { + $wanted[$matches[1].ToUpper()] = $line + } +} + +$root = (Get-Location).Path +$files = New-Object 'System.Collections.Generic.SortedSet[string]' ([System.StringComparer]::Ordinal) +$found = @{} + +# A single .cpp can hold several // FUNCTION: lines, so every match in every file is checked. +Get-ChildItem -Path $SourceRoot -Recurse -Filter *.cpp | Select-String -Pattern "//\s*FUNCTION:\s*\S+\s+0x([0-9A-Fa-f]+)" | ForEach-Object { + $address = $_.Matches[0].Groups[1].Value.ToUpper() + if ($wanted.ContainsKey($address)) { + $found[$address] = $true + [void]$files.Add($_.Path.Substring($root.Length + 1).Replace("\", "/")) + } +} + +foreach ($address in ($wanted.Keys | Sort-Object)) { + if (-not $found.ContainsKey($address)) { + Write-Warning "no .cpp found for: $($wanted[$address])" + } +} + +$target = Join-Path $root $Destination +$text = if ($files.Count -gt 0) { ($files -join "`n") + "`n" } else { "" } +[System.IO.File]::WriteAllText($target, $text, (New-Object System.Text.UTF8Encoding $false)) + +Write-Host "$($wanted.Count) incomplete functions -> $($files.Count) files written to $Destination" diff --git a/tools/reimplementation-helper/batch/README.md b/tools/reimplementation-helper/batch/README.md index 47cbbfa65..dd5d15cb3 100644 --- a/tools/reimplementation-helper/batch/README.md +++ b/tools/reimplementation-helper/batch/README.md @@ -15,12 +15,51 @@ rewrite sources, because the Visual Studio bundled one is too old for `.clang-fo | `build_quiet.py [--keep-going]` | `build.bat RelWithDebInfo OpenSHC.dll`, prints only errors and `BUILD_OK`/`BUILD_FAIL` (build.bat exits 0 even on errors). Retries once on a PDB server error, see the note below. | | `syntax_check.py [substr...]` | `cl /Zs` every (matching) list file serially; finds all compile errors in one pass without linking. | | `reccmp_report.py [--run] pct\|save\|cmp\|diff` | Match % and *normalized* % (call/tail-jump targets and resolver addresses ignored) per function, snapshots, before/after comparison, compact asm diffs. | +| `orig_asm.py NAME [--both\|--stats]` | The **original** instruction stream of one function (not the interleaved diff), in address order; `--stats` reports the tells that decide how to reimplement it: `mov reg, 0` (handwritten asm), frame pointer (built /Od), frame size, jump tables. | | `show_functions.py PREFIX [--skip-100]` | Print function bodies under `src/OpenSHC/PREFIX` with their percentages, in the block format `splice_functions.py` reads. | | `splice_functions.py BLOCKS.txt` | Replace many function bodies at once (keeps the `// FUNCTION:` line, can add includes/usings), then clang-format. | | `commit_progress_batch.py PREFIX... [Name=remark]` | One `reimplement:` commit per changed function with its status line, like `commit_progress`. | | `fix_func_refs.py [--drop-include H]` | After a header refactor: rewrite `X_Func::name` references whose resolver moved to another namespace. | | `move_to_resolver_namespace.py FILE...` | After a header refactor: re-wrap a definition in its resolver's new namespace and `git mv` it to the matching folder. | +Analysis helpers, for deciding *what* to change when a function is stuck below 100%: + +| Script | Purpose | +|---|---| +| `diff_triage.py [--run] [filter]` | One line per function: match %, raw and register/slot-normalized difflib ratios, `sub esp` frame size per side, byte-sized `[esp]` accesses per side, `ret` placement. Flags `FRAME` / `BYTE` / `RET` / `alloc-only`. | +| `diff_slots.py NAME` | Every `[esp + N]` slot with its access count on each side, and the slots only we use. Run after `diff_triage.py` reports `FRAME`. | +| `diff_jcc.py [NAME]` | Comparisons whose operator is one strictness step off the original (`jl`/`jle`, `jg`/`jge`, `ja`/`jae`) or whose `cmp` operands are the other way round, with context. | +| `diff_types.py [--run] [NAME]` | The non-comparison counterpart of `diff_jcc.py`: `movsx` against `movzx` for the same field (its signedness is wrong in the generated header), `add` against `sub` with the same magnitude (a sign error in a formula - how `2400/n + 40` was caught being `- 40`). It pairs only equal-length runs inside one reccmp block, so it stays quiet once the streams drift: it reports nothing across the 101 functions of `Game::GameStateStructures` and fires on both bugs when they are reintroduced. | +| `quick_diff.py FILE.cpp... [-q]` | Compile one file with `/FA` and diff it against the original function disassembled straight from `_original/` - about 6 seconds, no link and no reccmp, so a dozen source variants can be tried in the time of one build. Shows the whole original function, which reccmp's diff does not when ours is shorter. A triage loop: confirm a 1.0 with `reccmp_report.py --run`, and do not trust a *rise* of its ratio below about 0.6 - on a badly matching function difflib rewards a different alignment, and one such "gain" was a 10-point loss in reccmp. | +| `reorder_search.py FILE NAME [--pairs] [--dry]` | Hill-climb the match % by reordering independent statements: permute runs of >=3 by default, or swap every adjacent independent pair with `--pairs`. Builds once per move and reverts anything that does not improve. | + +### Choosing what to work on + +| Script | Purpose | +|---|---| +| `rank_functions.py [filter] [--top N]` | Rank by source lines x (1 - match), so the big badly-matching functions come first instead of the small ones with a low percentage. | +| `scan_dispatch.py [filter]` | Functions whose dispatch form disagrees with the original (jump table on one side, if/else-if chain on the other), and which way to fix each. | +| `scan_chains.py [filter] [--min N]` | `if/else if` chains comparing one expression against several constants: the candidates to convert when `scan_dispatch.py` says the original has a table we do not. | +| `try_styles.py FUNC [style...]` | Compile and measure several hand-written variants of one function, restore the winner, print the table. Variants live in `build-RelWithDebInfo/batch/variants/FUNC/*.cpp`. | + +### Readability passes + +These undo decompiler artefacts. Each measured as code-generation neutral or better where +it was applied, but none is guaranteed to be -- re-measure after running one. + +| Script | Purpose | +|---|---| +| `declare_at_use.py [filter]` | Move the leading declaration block down to each variable's first use, and drop declarations that are never used. Only moves one when the first assignment provably dominates every later use. | +| `decast.py [filter]` | Collapse doubled casts, `(int)((int)(x))` -> `(int)(x)`. Skips `(int)((int)X + Y)`, where the inner cast covers one operand and dropping it would move the conversion onto the sum. | +| `deparen.py [filter] [--apply]` | Drop redundant brackets from `if`/`while` conditions using C precedence. Keeps the load-bearing ones (`(a \|\| b) && c`, `(x & 7) == 0`, assignments and comma operators inside conditions). Dry run unless `--apply`. | +| `test_deparen.py` | Precedence tests for `deparen.py`. Run after touching its table: an earlier version silently rewrote `(a != 0 \|\| b != 0) && (x & 0x100) == 0` into a different expression that still compiled. | +| `undiv.py [filter] [--apply]` | Turn MSVC's biased shift for a signed power-of-two division back into a division: `(x + (x >> 0x1f & 7U)) >> 3` -> `x / 8`. Dry run unless `--apply`. Usually a large gain rather than merely neutral: over one namespace it was worth up to 22% on a single function. | +| `test_undiv.py` | Cases for `undiv.py`, including the near-misses it must leave alone: a shift disagreeing with the mask, a mask that is not 2^k - 1, and a bias taken from another variable. | +| `unmod.py [filter] [--apply]` | The same for a signed power-of-two remainder: `v = x & 0x8000000f;` plus the negative-case repair is `v = x % 16`. Forces a signed dividend, because the repair only exists for a signed operand and an unsigned `%` compiles to a bare `and`. | +| `test_unmod.py` | Cases for `unmod.py`: a repair constant that does not complement the mask, a repair applied to another variable, and a bare mask with no repair. | +| `unptr.py [filter] [--apply]` | Replace the decompiler's field-walking pointers (`piVar1 = &x.f; *piVar1 = *piVar1 + 1;`) with the field itself. Only the two-adjacent-line shape, since a pointer freezes the address while the field form re-evaluates the index. Reports which pointers are still in use. | +| `test_unptr.py` | Cases for `unptr.py`, including a pointer declared on the spot (`char* pcVar3 = &...`, whose type prefix must go with it) and the set-up-then-use-later shape it must leave alone. | + ## Typical loop ```sh @@ -33,6 +72,27 @@ python reccmp_report.py diff someFunction # inspe python commit_progress_batch.py Map/Units "someFunction=LTCG ecx reuse" ``` +## Reading `diff_triage.py` + +The two ratios are the quickest way to tell whether more source work can pay: + +- `norm` much higher than `raw` - only register and stack-slot *naming* differs. + The allocator is not reachable from the source; record the reason and move on. +- `norm` still low - real structure or ordering differs; keep looking. +- `FRAME` - one local too many or too few. Chase it with `diff_slots.py`; this has + been worth 10-30 points (a redundant Ghidra temp, or two copies of a parameter + where the original introduced fresh locals instead of reassigning it). +- `BYTE` - we have byte-sized stack slots the original does not: every `bool`/`byte` + local is an `int` in the original. +- `RET` - we inline a cold early-return block the original places out of line. + Restructure so the cold case is last in the source (`if (ok) { body } else { reset }` + rather than a guard at the top), which is what makes MSVC outline it. + +Confirm a `diff_jcc.py` fix by re-running that tool and checking the pair is gone, +not by the percentage: a single instruction moves the score by ~0.1 and tells you +nothing, while three such fixes in one namespace turned out to be real off-by-one +bugs that Ghidra had decompiled wrongly. + ## Notes - `normalized 100%` means only call-target differences remain. `commit_progress_batch.py` @@ -44,6 +104,12 @@ python commit_progress_batch.py Map/Units "someFunction=LTCG ecx reuse" (`common.build_env`), the same name `build.bat` derives. `mspdbsrv.exe` is a per-user singleton keyed on that endpoint and each worktree carries its own toolchain copy, so a shared endpoint makes `cl.exe` talk to the wrong server and fail with - `fatal error C1090: PDB API call failed`. `build_quiet.py` retries once after stopping - this worktree's `mspdbsrv.exe` (`common.kill_pdb_server`, never other worktrees'), which - clears a server that was already wedged before the build started. + `fatal error C1090: PDB API call failed`. +- `build_quiet.py` and `syntax_check.py` both retry such a failure twice, because it has two + causes. A wedged server survives the kill `build.bat` does up front, so the first retry stops + this worktree's `mspdbsrv.exe` (`common.kill_pdb_server`, never other worktrees'). A wedged + *endpoint* outlives every `mspdbsrv.exe` using it, so the second retry moves to a fresh name + (`common.fresh_pdb_endpoint`) rather than retrying into one that will keep failing. +- In `syntax_check.py` a PDB failure is not just a lost run: the fatal line counts as an error + against whichever file hit it and the rest of the batch still gets checked, so without the + retries the output looks like a normal error list and hides the real compile errors. diff --git a/tools/reimplementation-helper/batch/build_quiet.py b/tools/reimplementation-helper/batch/build_quiet.py index 7e29e9fd9..76fd17a59 100644 --- a/tools/reimplementation-helper/batch/build_quiet.py +++ b/tools/reimplementation-helper/batch/build_quiet.py @@ -18,6 +18,11 @@ The second cost six consecutive builds once, across a regenerated PCH and PDBs, while the same tree built first try under a different endpoint name. + +A build that fails without naming any source line gets one more plain retry. cmake's glob +verification dies with an access violation ("Access violation" + U1077 return code 0xffffffff) on the +first build after cmake/openshc-sources.txt.local changes, which is every first build of a new +selection; the reconfigure crashed, not the compile, and a plain re-run succeeds. """ import argparse @@ -60,8 +65,26 @@ def run_build(endpoint=None): kill_pdb_server() text = run_build(endpoint) -errors = [line for line in text.splitlines() - if re.search(r" error |warning C4700|warning C4715", line) and "U1077" not in line] +def compile_errors(text): + return [line for line in text.splitlines() + if re.search(r" error |warning C4700|warning C4715", line) and "U1077" not in line] + + +def failing(text): + return bool(re.search(r" error |U1077", text)) + + +if failing(text) and not compile_errors(text): + # Nothing named a source line, so the compile is not what failed: cmake's glob verification + # crashed during the reconfigure. It succeeds on a plain re-run. + print("note: build failed without a compiler error, retrying once", file=sys.stderr) + text = run_build() + +errors = compile_errors(text) for line in errors[:args.max]: print(re.sub(r"^.*src.OpenSHC.", "", line)) -print("BUILD_FAIL" if re.search(r" error |U1077", text) else "BUILD_OK") +failed = failing(text) +print("BUILD_FAIL" if failed else "BUILD_OK") +# exit non-zero so `build_quiet.py && reccmp_report.py ...` stops here: a failed build +# leaves the previous DLL in place and reccmp would happily report on the old code +raise SystemExit(1 if failed else 0) diff --git a/tools/reimplementation-helper/batch/common.py b/tools/reimplementation-helper/batch/common.py index 64406b95c..3e15e3d9d 100644 --- a/tools/reimplementation-helper/batch/common.py +++ b/tools/reimplementation-helper/batch/common.py @@ -147,7 +147,28 @@ def run_reccmp(): sys.exit("reccmp failed:\n" + result.stdout[-800:] + result.stderr[-800:]) +def warn_if_stale(): + """Warn when diff.json predates a source file it is supposed to describe. + + build.bat exits 0 even when compilation failed, so a failed build leaves the previous + DLL and the previous diff.json in place and every reccmp number silently describes the + code as it was before the edit. That has been mistaken for "the change was neutral" + more than once, so say it out loud. + """ + try: + built = DIFF_JSON.stat().st_mtime + except OSError: + return + newer = [f for f in list_files() if Path(f).exists() and Path(f).stat().st_mtime > built] + if newer: + sys.stderr.write( + "warning: %d source file(s) are newer than the last reccmp run, e.g. %s.\n" + " Re-build (and check for BUILD_FAIL) before trusting these numbers.\n" + % (len(newer), newer[0])) + + def load_diff(): + warn_if_stale() return {int(e["address"], 16): e for e in json.loads(DIFF_JSON.read_text())["data"]} diff --git a/tools/reimplementation-helper/batch/decast.py b/tools/reimplementation-helper/batch/decast.py new file mode 100644 index 000000000..f473c5a25 --- /dev/null +++ b/tools/reimplementation-helper/batch/decast.py @@ -0,0 +1,96 @@ +"""Collapse the decompiler's doubled casts, e.g. (int)((int)(x)) -> (int)(x). + +Only a cast applied to a *whole* casted operand is removed. `(int)((int)X + Y)` looks the +same textually but is not a doubled cast: there the inner cast covers X alone, and +dropping it moves the conversion onto the sum, which changes the generated code. The +`sole_operand` check rejects those. + +Measured as code-generation neutral over the UnitsState namespace (19 casts, no change in +any function), so it is a readability pass -- but re-measure after running it. + +usage: + decast.py [path-filter] +""" + +import sys + +import common + +path_filter = sys.argv[1] if len(sys.argv) > 1 else "" + +# (outer, inner) pairs where dropping the inner cast cannot change the conversion +PAIRS = [("int", "int"), ("uint", "uint"), ("short", "short"), ("ushort", "ushort"), + ("uint", "int"), ("int", "uint"), ("short", "int"), ("ushort", "int")] + + +def match_paren(s, i): + depth = 0 + while i < len(s): + if s[i] == "(": + depth += 1 + elif s[i] == ")": + depth -= 1 + if depth == 0: + return i + i += 1 + raise ValueError("unbalanced") + + +def is_group(s): + s = s.strip() + return s.startswith("(") and match_paren(s, 0) == len(s) - 1 + + +def sole_operand(s): + """True if s is one operand rather than part of a wider expression.""" + s = s.strip() + if is_group(s): + return True + depth = 0 + for ch in s: + if ch in "([": + depth += 1 + elif ch in ")]": + depth -= 1 + elif depth == 0 and ch in "+-*/%&|^<>=!?,": + return False + return True + + +def collapse_once(text): + for outer, inner in PAIRS: + needle = "(%s)((%s)" % (outer, inner) + i = text.find(needle) + while i != -1: + try: + close = match_paren(text, i + len(outer) + 2) + except ValueError: + i = text.find(needle, i + 1) + continue + rest = text[i + len(outer) + 3:close][len(inner) + 2:].strip() + if rest and sole_operand(rest): + body = rest if is_group(rest) else "(%s)" % rest + return text[:i] + "(%s)%s" % (outer, body) + text[close + 1:], True + i = text.find(needle, i + 1) + return text, False + + +total = 0 +for f in common.list_files(): + if path_filter not in f: + continue + text = common.read_text(f).replace("\r\n", "\n") + n = 0 + while True: + text, changed = collapse_once(text) + if not changed: + break + n += 1 + if n > 200: + sys.exit("%s: not converging" % f) + if n: + common.write_text(f, text) + common.format_file(f) + print("%-52s %d" % (f.rsplit("/", 1)[-1][:-4], n)) + total += n +print("%d doubled cast(s) collapsed" % total) diff --git a/tools/reimplementation-helper/batch/declare_at_use.py b/tools/reimplementation-helper/batch/declare_at_use.py new file mode 100644 index 000000000..39741e74d --- /dev/null +++ b/tools/reimplementation-helper/batch/declare_at_use.py @@ -0,0 +1,101 @@ +"""Move a function's leading declaration block down to each variable's first use. + +The decompiler declares everything at the top; the original declared at first use. This +merges the declaration into the first assignment wherever the scope allows it, and drops +declarations that are never used at all. + +Unlike a plain "single assignment" rule this also handles variables assigned more than +once: only the *first* assignment has to dominate every later use, which is checked by +tracking brace depth from that assignment to the last use. Anything it cannot prove is +left alone and reported, so the output doubles as a list of what still needs a hand. + +Declaration position does not change code generation, so this is a readability pass; run +it before measuring, not instead of. + +usage: + declare_at_use.py [path-filter] +""" + +import re +import sys + +import common + +path_filter = sys.argv[1] if len(sys.argv) > 1 else "" + +DECL = re.compile(r"^(?P(?:unsigned\s+|const\s+)*[A-Za-z_][\w:]*)\s+" + r"(?P\**)\s*(?P[A-Za-z_]\w*)\s*" + r"(?P\[[^\]]*\])?\s*;$") + + +def depths(lines): + out, d = [], 0 + for line in lines: + out.append(d) + code = re.sub(r"//.*", "", line) + d += code.count("{") - code.count("}") + return out + + +def move(path): + text = common.read_text(path).replace("\r\n", "\n") + brace = re.compile(r"\n[ \t]*\{[ \t]*\n").search(text, text.index("// FUNCTION:")) + if not brace: + return None + head, lines = text[:brace.end()], text[brace.end():].split("\n") + + decls, i = [], 0 + while i < len(lines): + stripped = lines[i].strip() + if not stripped: + i += 1 + continue + m = DECL.match(stripped) + if not m: + break + decls.append((m.group("name"), m.group("type"), m.group("ptr") or "", + m.group("arr") or "", i)) + i += 1 + if not decls: + return None + + drop = set() + for var, vtype, ptr, arr, decl_at in decls: + word = re.compile(r"(?=", "<", ">"]] +COMPARISON = 7 # index in LEVELS of ==/!=; anything at or past this is a comparison + + +def match_paren(s, i): + depth = 0 + while i < len(s): + if s[i] in "([": + depth += 1 + elif s[i] in ")]": + depth -= 1 + if depth == 0: + return i + i += 1 + return -1 + + +def scan_top(s): + """Yield (index, level, token) for every top-level operator.""" + i = 0 + while i < len(s): + if s[i] in "([": + j = match_paren(s, i) + i = (j + 1) if j != -1 else i + 1 + continue + for level, tokens in enumerate(LEVELS): + hit = None + for tok in tokens: + if not s.startswith(tok, i): + continue + if tok == "=" and (s[i - 1:i] in "=!<>" or s[i + 1:i + 2] == "="): + continue + if tok in ("<", ">") and s[i - 1:i + 1] == "->": + continue + hit = tok + break + if hit: + yield i, level, hit + i += len(hit) - 1 + break + i += 1 + + +def rank(s): + """Level of the loosest top-level operator, or len(LEVELS) when there is none.""" + best = len(LEVELS) + for _, level, _ in scan_top(s): + best = min(best, level) + return best + + +def split_top(s, tok): + parts, last = [], 0 + for idx, _, t in scan_top(s): + if t == tok and idx >= last: + parts.append(s[last:idx]) + last = idx + len(tok) + parts.append(s[last:]) + return parts + + +def is_group(s): + s = s.strip() + return s.startswith("(") and match_paren(s, 0) == len(s) - 1 + + +def simplify(expr): + """Simplify inside expr. Its own outer brackets are the caller's to judge, since only + the caller knows which operator binds it to its siblings.""" + expr = expr.strip() + r = rank(expr) + if r >= len(LEVELS): + return expr + tokens = [t for _, level, t in scan_top(expr) if level == r] + if not tokens or any(t != tokens[0] for t in tokens): + return expr # mixed operators at one level: leave it + tok = tokens[0] + out = [] + for part in split_top(expr, tok): + part = part.strip() + while is_group(part): + inner = part[1:-1].strip() + ri = rank(inner) + if ri <= 1 or not (ri == r or ri >= COMPARISON): + break + part = inner + out.append(simplify(part)) + return (" %s " % tok).join(out) + + +CONDITION = re.compile(r"(?m)^(\s*)(\}\s*else\s+)?(if|while)\s*\(") + + +def process(text): + out, pos, n = [], 0, 0 + for m in CONDITION.finditer(text): + if m.start() < pos: + continue + open_at = text.index("(", m.end() - 1) + close_at = match_paren(text, open_at) + if close_at == -1: + continue + flat = " ".join(text[open_at + 1:close_at].split()) + # the if's own brackets already group the whole condition, so one redundant layer + # directly inside them can always go + outer = flat + while is_group(outer) and rank(outer[1:-1]) > 1: + outer = outer[1:-1].strip() + new = simplify(outer) + if new != flat and ("((" in flat or "))" in flat): + out.append(text[pos:open_at + 1]) + out.append(new) + pos = close_at + n += 1 + out.append(text[pos:]) + return "".join(out), n + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("path_filter", nargs="?", default="") + parser.add_argument("--apply", action="store_true") + args = parser.parse_args() + + total = 0 + for f in common.list_files(): + if args.path_filter not in f: + continue + new, n = process(common.read_text(f).replace("\r\n", "\n")) + if not n: + continue + print("%-52s %d" % (f.rsplit("/", 1)[-1][:-4], n)) + total += n + if args.apply: + common.write_text(f, new) + common.format_file(f) + print("%d condition(s) simplified%s" % (total, "" if args.apply else " (dry run, pass --apply)")) diff --git a/tools/reimplementation-helper/batch/diff_jcc.py b/tools/reimplementation-helper/batch/diff_jcc.py new file mode 100644 index 000000000..aaaa3f202 --- /dev/null +++ b/tools/reimplementation-helper/batch/diff_jcc.py @@ -0,0 +1,84 @@ +"""Find comparisons whose operator or operand order is one step off the original. + +usage: diff_jcc.py [NAME-SUBSTRING] + +Reports two kinds of pair, each with the four preceding instructions so the +site can be found in the source: + + JCC the two sides differ by one strictness step (jl/jle, jg/jge, ja/jae) + or are direction-flipped (jl/jge). A strictness step is a real + off-by-one in the source: write the literal and operator the original + shows, e.g. `cmp x,0xa0; jle` is `x <= 160`, not `x < 160`. + CMP the same two operands compared the other way round; swap the sides of + the comparison in the source. + +This has found genuine bugs where Ghidra's decompilation was wrong, so confirm +a fix by re-running this tool and checking the pair is gone - the match +percentage barely moves for a single instruction and tells you nothing. + +Two pairs it reports are NOT source bugs, so check the context before editing: + * `orig jl / ours jge` where both sides share the `cmp` is block placement, + not an operator - the original puts the if-body out of line and jumps to + it. Fix that by moving the cold case last in the source, not by flipping + the test. + * `orig jns / ours jge` right after an `and` is the same thing twice; the + `and` clears OF so the two encodings are equivalent. +""" + +import re +import sys + +import common + +JCC = re.compile(r"^(j[a-z]+)\s") +CMP = re.compile(r"^cmp (.+?), (.+)$") +STEP = {("jl", "jle"), ("jle", "jl"), ("jg", "jge"), ("jge", "jg"), + ("ja", "jae"), ("jae", "ja"), ("jb", "jbe"), ("jbe", "jb"), + ("jl", "jge"), ("jge", "jl"), ("jg", "jle"), ("jle", "jg")} + +want = sys.argv[1] if len(sys.argv) > 1 else "" + + +def stream(entry): + """Interleaved (kind, text, source-annotation) in emission order. + + Pairing an `orig` line with the `recomp` line that immediately follows it is + the only sound comparison; indexing `block['orig'][i]` against + `block['recomp'][i]` invents pairs out of unrelated instructions. + """ + out = [] + for hunk in entry.get("diff") or []: + for block in hunk[1]: + for kind, rows in block.items(): + for row in rows: + text = row[1] + src = text.split("\t")[1].strip() if "\t" in text else "" + out.append((kind, text.split("\t")[0].strip(), src)) + return out + + +for f, e, address in common.entries(common.load_diff()): + if e is None or (want and want not in e["name"]) or not e.get("diff"): + continue + rows = stream(e) + hits = [] + for i in range(len(rows) - 1): + k1, a, _ = rows[i] + k2, c, src = rows[i + 1] + if k1 != "orig" or k2 != "recomp": + continue + ja, jc = JCC.match(a), JCC.match(c) + if ja and jc and (ja.group(1), jc.group(1)) in STEP: + hits.append(("JCC orig %-4s / ours %-4s" % (ja.group(1), jc.group(1)), src, i)) + continue + ma, mc = CMP.match(a), CMP.match(c) + if ma and mc and ma.group(1).strip() == mc.group(2).strip() and ma.group(2).strip() == mc.group(1).strip(): + hits.append(('CMP orig "%s" / ours "%s"' % (a, c), src, i)) + if not hits: + continue + print("### %s %.1f%%" % (e["name"].split("::")[-1], float(e["matching"]) * 100)) + for tag, src, i in hits: + print(" %-38s %s" % (tag, src)) + for j in range(max(0, i - 4), i): + kind, text, ann = rows[j] + print(" %-7s %-58s %s" % (kind, text[:58], ann)) diff --git a/tools/reimplementation-helper/batch/diff_slots.py b/tools/reimplementation-helper/batch/diff_slots.py new file mode 100644 index 000000000..a13225cb3 --- /dev/null +++ b/tools/reimplementation-helper/batch/diff_slots.py @@ -0,0 +1,41 @@ +"""Census of the `[esp + N]` slots each side touches, to find a local too many. + +usage: diff_slots.py NAME-SUBSTRING + +Prints every stack slot with how often it is accessed, on the original and on +our side. Use it after diff_triage.py reports a FRAME mismatch: one extra +distinct slot on our side is one local the original does not have, and the slot +with the lowest access count is usually the culprit. Grep the diff for that +slot to see what writes it - a 16-bit `mov word ptr [esp+N]` means a `short` +local the original keeps in a register or widens to `int`. +""" + +import re +import sys + +import common + +if len(sys.argv) < 2: + sys.exit(__doc__) +want = sys.argv[1] +SLOT = re.compile(r"\[esp \+ (0x[0-9a-f]+)\]") + +for f, e, address in common.entries(common.load_diff()): + if e is None or want not in e["name"] or not e.get("diff"): + continue + orig, ours = common._asm_lines(e) + counts = [] + for stream in (orig, ours): + c = {} + for line in stream: + for m in SLOT.finditer(line): + v = int(m.group(1), 16) + c[v] = c.get(v, 0) + 1 + counts.append(c) + o, u = counts + print("### %s %.1f%%" % (e["name"], float(e["matching"]) * 100)) + print(" orig %2d slots: %s" % (len(o), " ".join("%#x:%d" % kv for kv in sorted(o.items())))) + print(" ours %2d slots: %s" % (len(u), " ".join("%#x:%d" % kv for kv in sorted(u.items())))) + only_ours = sorted(set(u) - set(o)) + if only_ours: + print(" only ours: %s" % " ".join("%#x (%d uses)" % (k, u[k]) for k in only_ours)) diff --git a/tools/reimplementation-helper/batch/diff_triage.py b/tools/reimplementation-helper/batch/diff_triage.py new file mode 100644 index 000000000..5c832cf4a --- /dev/null +++ b/tools/reimplementation-helper/batch/diff_triage.py @@ -0,0 +1,97 @@ +"""Decide where source work can still help, per function in cmake/openshc-sources.txt.local. + +usage: diff_triage.py [--run] [path-filter] + +Columns, all derived from the last reccmp run: + + pct reccmp match % + raw difflib ratio over the two instruction streams + norm the same ratio after renaming registers to R, `[esp + 0xN]` to [SLOT] + and literals to N + frame `sub esp, N` on each side + byte number of byte-sized `[esp]` accesses on each side + ret position of each `ret`, as a fraction of the stream + +How to read it: + + norm >> raw only register/stack-slot naming is left; stop editing + the source, the allocator is not reachable from it + norm still low real structure or ordering differs; keep looking + frame differs one local too many or too few - chase it with + diff_slots.py, this has been worth 10-30 points + byte on our side only every bool/byte local is an int in the original + ret positions differ we inline a cold early-return block the original + outlines (or the reverse); restructure the guard so the + cold case is last in the source +""" + +import re +import sys + +import common + +REG = re.compile(r"\b(e?[abcd]x|e?[sd]i|e?bp|e?sp|[abcd][lh])\b") +BYTE_SLOT = re.compile(r"(^|[^d])byte ptr \[esp") +FRAME = re.compile(r"^sub esp, (0x[0-9a-f]+|\d+)") + +args = sys.argv[1:] +if args and args[0] == "--run": + common.run_reccmp() + args = args[1:] +path_filter = args[0] if args else "" + + +def normalize(line): + s = line.split("\t")[0].strip() + s = REG.sub("R", s) + s = re.sub(r"\[R \+ 0x[0-9a-f]+\]", "[SLOT]", s) + s = re.sub(r"0x[0-9a-f]+", "N", s) + return re.sub(r"\b\d+\b", "N", s) + + +def frame_of(stream): + for line in stream: + m = FRAME.match(line.split("\t")[0].strip()) + if m: + return m.group(1) + return "-" + + +def ret_positions(stream): + hits = [i for i, t in enumerate(stream) if t.split("\t")[0].strip().startswith("ret")] + return [round(i / max(1, len(stream)), 2) for i in hits][:6] + + +import difflib # noqa: E402 (after common, which chdirs to the repo root) + +rows = [] +for f, e, address in common.entries(common.load_diff()): + if e is None or path_filter not in f or not e.get("diff"): + continue + orig, ours = common._asm_lines(e) + raw = difflib.SequenceMatcher(None, orig, ours, autojunk=False).ratio() + nrm = difflib.SequenceMatcher(None, [normalize(x) for x in orig], + [normalize(x) for x in ours], autojunk=False).ratio() + fo, fu = frame_of(orig), frame_of(ours) + bo = sum(1 for t in orig if BYTE_SLOT.search(t)) + bu = sum(1 for t in ours if BYTE_SLOT.search(t)) + ro, ru = ret_positions(orig), ret_positions(ours) + flags = [] + if fo != fu: + flags.append("FRAME") + if bu > bo: + flags.append("BYTE") + if ro != ru and (len(ro) != len(ru) or any(abs(a - b) > 0.08 for a, b in zip(ro, ru))): + flags.append("RET") + if not flags and nrm - raw > 0.25: + flags.append("alloc-only") + rows.append((float(e["matching"]), e["name"].split("::")[-1], raw, nrm, fo, fu, bo, bu, ro, ru, flags)) + +rows.sort() +print("%-38s %5s %6s %6s %-6s %-6s %4s %4s %s" % + ("function", "pct", "raw", "norm", "frmO", "frmU", "byO", "byU", "flags")) +for m, name, raw, nrm, fo, fu, bo, bu, ro, ru, flags in rows: + print("%-38s %5.1f %6.3f %6.3f %-6s %-6s %4d %4d %s" % + (name, m * 100, raw, nrm, fo, fu, bo, bu, " ".join(flags))) + if "RET" in flags: + print("%-38s orig ret %s ours ret %s" % ("", ro, ru)) diff --git a/tools/reimplementation-helper/batch/diff_types.py b/tools/reimplementation-helper/batch/diff_types.py new file mode 100644 index 000000000..54049f9f2 --- /dev/null +++ b/tools/reimplementation-helper/batch/diff_types.py @@ -0,0 +1,140 @@ +"""Find differences that point at a wrong type, addressing mode or constant, per function in +cmake/openshc-sources.txt.local. + +usage: diff_types.py [--run] [NAME-SUBSTRING] + +`diff_jcc.py` covers comparisons and `diff_triage.py` covers frames and slots; this covers the three +remaining classes that have a source-level fix: + + EXTEND `movsx` on one side and `movzx` on the other for the same operand. The field's + signedness is wrong in the generated header: `char` vs `byte`, `short` vs `ushort`. + Commit header retypes separately from the .cpp work. + SIGNFLIP `add` against `sub` of the same magnitude on the same destination: a sign error in a + formula. Trust the asm over the decompilation - Ghidra rendered `2400 / n + 40` where the + binary has `sub eax, 0x28`, so the formula was `- 40`, and the function reached 100% once + corrected. +A third class, `this->` against the global instance, is deliberately not reported. One function often +reads some fields through `this` and others through `DAT_*::instance`, in both directions at once, so +counting anchored operands fires for almost every function and proves nothing about any single +access. Read it off `reccmp_report.py diff` instead: a `this`-relative operand on one side against a +`StructResolver::Instance<..>` symbol on the other, for the *same* field, is the signal. That needs +the global data reimplementations switched on (the `MACRO_STRUCT_RESOLVER` flag in +`src/OpenSHC/Globals/*.hpp`, never committed); with them off every absolute address looks alike. + +Instructions are paired inside one reccmp replacement block and only when both sides have the same +number of that kind of line. Once the streams drift, the n-th instruction on each side is no longer +the same instruction, and pairing them invents differences that are not there. Confirm every hit +against `reccmp_report.py diff` before editing. + +Both rules were checked in both directions: they fire on the two known bugs when those are +reintroduced (a `char` layer that should be `byte`, and `+ 40` that should be `- 40`) and report +nothing across the 101 functions of `Game::GameStateStructures` once fixed. A third rule, "same +instruction with a different constant", was tried and removed: every one of its hits on that folder +was a loop-induction stride (`imul reg, 0x39f4` against a different element size, `add reg, 4` +against `add reg, 0x14`), never a constant the source chose. + +--run re-runs reccmp first (otherwise reccmp/dll/diff.json from the last run is used). +""" + +import re +import sys + +import common + +IMM_RE = re.compile(r"(-?0x[0-9a-f]+|(?::instance+N]` and `movsx eax, byte ptr [ebx + esi + I::instance+N]` + reach the same array, so only the width and the symbol identify the access. + """ + m = re.search(r"(byte|word|dword) ptr \[(.*)\]", s) + if not m: + return None + inner = re.sub(r"\b(e?[abcd]x|e?[sd]i|e?[sb]p)\b(\*\d)?\s*\+?\s*", "", m.group(2)) + return m.group(1), inner.strip() + + +def blocks(entry): + """[(orig_lines, recomp_lines)] per replacement block.""" + pairs = [] + for hunk in entry.get("diff") or []: + for block in hunk[1]: + o = [op(r[1]) for r in block.get("orig", [])] + r = [op(r[1]) for r in block.get("recomp", [])] + if o and r: + pairs.append((o, r)) + return pairs + + +def hints_for(entry): + pairs = blocks(entry) + hits = [] + + def add(cls, a, b): + if (cls, a, b) not in hits and len(hits) < 25: + hits.append((cls, a, b)) + + def zip_kind(o, r, keep): + a = [x for x in o if keep(x)] + b = [x for x in r if keep(x)] + return list(zip(a, b)) if len(a) == len(b) else [] + + for o, r in pairs: + # EXTEND: same width and same symbol/displacement, different extension. Base registers are + # ignored on purpose - the two sides often reach the same array through different registers, + # and requiring those to match was what made this miss real cases. + for a, b in zip_kind(o, r, lambda x: x.startswith(("movsx ", "movzx "))): + if a.split()[0] != b.split()[0] and mem_shape(a) == mem_shape(b): + add("EXTEND", a, b) + # SIGNFLIP: add against sub (or the reverse) on the same destination with the same magnitude. + # This is what a wrong sign in a formula looks like; the constant itself is identical, so the + # CONST rule below can never see it. + for a, b in zip_kind(o, r, lambda x: x.startswith(("add ", "sub ")) and IMM_RE.search(x)): + ma, mb = IMM_RE.search(a), IMM_RE.search(b) + if (a.split()[0] != b.split()[0] and ma.group(1) == mb.group(1) + and scrub_regs(a[len(a.split()[0]):ma.start()]) + == scrub_regs(b[len(b.split()[0]):mb.start()])): + add("SIGNFLIP", a, b) + return hits + + +def main(): + args = sys.argv[1:] + if args and args[0] == "--run": + common.run_reccmp() + args = args[1:] + want = args[0] if args else "" + byaddr = common.load_diff() + shown = total = 0 + for f, e, a in common.entries(byaddr): + if e is None or float(e["matching"]) >= 1 or want not in e["name"]: + continue + total += 1 + hits = hints_for(e) + if not hits: + continue + shown += 1 + print("### %s %.1f%% norm %.1f%%" + % (e["name"], float(e["matching"]) * 100, common.normalized_ratio(e) * 100)) + for cls, x, y in hits: + print(" %-8s orig: %-44s ours: %s" % (cls, x, y)) + if not total: + print("nothing below 100% in the current list") + else: + print("\n%d of %d function(s) below 100%% have a type or sign hint" % (shown, total)) + + +if __name__ == "__main__": + main() diff --git a/tools/reimplementation-helper/batch/orig_asm.py b/tools/reimplementation-helper/batch/orig_asm.py new file mode 100644 index 000000000..40bd6e4fb --- /dev/null +++ b/tools/reimplementation-helper/batch/orig_asm.py @@ -0,0 +1,137 @@ +"""Print the ORIGINAL instruction stream of one function from the current reccmp diff. + +`reccmp_report.py diff NAME` shows an interleaved diff, which is what you want while closing a +small gap. It is the wrong tool when you need to read the original on its own: + + * the diff only covers instructions reccmp chose to align, so long functions come back truncated; + * reconstructing control flow (a switch, a loop nest, a hand-written asm block) needs the + original's own jump targets and fall-through order, which the interleaving hides. + +This prints just the original side, in address order, so it can be read or grepped like a listing. +It needs no Ghidra connection - it reuses `reccmp/dll/diff.json` from the last +`reccmp_report.py --run` - so it also works when the Ghidra MCP server is down. + +usage: + orig_asm.py NAME [--both] # NAME matches the end of the reccmp symbol name + orig_asm.py NAME --stats # instruction count and the tells for a handwritten original + +`--both` also prints the instructions reccmp matched, marked "=", so the output is the full original +body rather than only the parts that differ. + +`--stats` reports the signals that decide how a function has to be reimplemented at all: + * "mov reg, 0" - no compiler materialises zero that way; the block is handwritten assembly + and belongs in an __asm block (see AGENTS.md and NeighbourFlagsAsm.hpp). + * frame pointer - "push ebp / mov ebp, esp" with locals addressed off ebp means the original + was built without optimisation; the reimplementation needs + #pragma optimize("", off). The same prologue with "and esp, -N" is only + /O2 realigning the stack for a large local, and is NOT an /Od tell. + * "sub esp, N" - the frame size. Matching it exactly is usually the single biggest win for + an unoptimised function, because every local displacement shifts otherwise. + * "jmp dword ptr" - a jump table: Ghidra often renders the dispatch as a call through an + unnamed pointer array and drops the arms, so the switch must be rebuilt + from the byte/jump tables rather than restyled from the decompiler output. +""" + +import io +import json +import re +import sys + +import common + +USAGE = 'usage: orig_asm.py NAME [--both|--stats]' + + +def find(node, name): + """Locate the diff entry whose symbol name ends with `name`.""" + if isinstance(node, dict): + if str(node.get('name', '')).endswith(name): + return node + for value in node.values(): + hit = find(value, name) + if hit: + return hit + elif isinstance(node, list): + for value in node: + hit = find(value, name) + if hit: + return hit + return None + + +def instructions(entry, both): + """Yield (address, text, matched) for the original side, in address order. + + The payload is a list of hunks; each hunk is [header, [group, ...]] and each group is + {"orig"|"both"|"recomp": [[address, text] or [address, text, recomp_address], ...]}. + """ + out = [] + + def walk(node): + if isinstance(node, dict): + for key in ('orig', 'both'): + if key not in node: + continue + if key == 'both' and not both: + continue + for row in node[key]: + if not (isinstance(row, (list, tuple)) and len(row) >= 2): + continue + # reccmp leaves the address empty on rows it synthesised (padding, + # and the blank line it puts between hunks); keep them in order by + # reusing the previous address rather than dropping the instruction. + try: + address = int(row[0], 16) + except (TypeError, ValueError): + address = out[-1][0] if out else 0 + out.append((address, row[1].rstrip(), key == 'both')) + elif isinstance(node, list): + for item in node: + walk(item) + + walk(entry['diff']) + out.sort(key=lambda row: row[0]) + return out + + +def main(): + args = [a for a in sys.argv[1:] if not a.startswith('--')] + flags = {a for a in sys.argv[1:] if a.startswith('--')} + if len(args) != 1 or flags - {'--both', '--stats'}: + sys.exit(USAGE) + name = args[0] + + if not common.DIFF_JSON.exists(): + sys.exit('%s not found; run reccmp_report.py --run pct first' % common.DIFF_JSON) + entry = find(json.load(io.open(str(common.DIFF_JSON), encoding='utf-8')), name) + if entry is None: + sys.exit('no reccmp entry whose name ends with %r' % name) + + rows = instructions(entry, both='--both' in flags or '--stats' in flags) + print('# %s %s %.2f%%' % (entry['name'], entry['address'], float(entry['matching']) * 100)) + + if '--stats' in flags: + text = '\n'.join(row[1] for row in rows) + zero = re.findall(r'\bmov e[a-z]{2}, 0\b', text) + # `push ebp / mov ebp, esp` alone is not an /Od tell: /O2 emits the same pair when a + # function realigns the stack for a large local (`and esp, -N`, usually with __chkstk), + # and there the locals still live at [esp + N]. A real /Od frame addresses them off ebp. + prologue = bool(re.search(r'\bpush ebp\b', text)) and bool(re.search(r'\bmov ebp, esp\b', text)) + realigned = bool(re.search(r'\band esp, 0x[0-9a-f]+\b', text)) + ebp_locals = bool(re.search(r'\[ebp - 0x[0-9a-f]+\]', text)) + frame = prologue and ebp_locals and not realigned + stack = re.findall(r'\bsub esp, (0x[0-9a-f]+|\d+)\b', text) + tables = re.findall(r'\bjmp dword ptr\b', text) + print('# instructions seen: %d (matched and differing)' % len(rows)) + print('# mov reg, 0 : %d%s' % (len(zero), ' <- handwritten assembly' if zero else '')) + print('# frame pointer : %s%s' % (frame, ' <- built /Od; use #pragma optimize' if frame else '')) + print('# frame size : %s' % (', '.join(stack) if stack else 'none')) + print('# jump tables : %d%s' % (len(tables), ' <- rebuild the switch by hand' if tables else '')) + return + + for address, text, matched in rows: + print('%08x %s %s' % (address, '=' if matched else '-', text)) + + +if __name__ == '__main__': + main() diff --git a/tools/reimplementation-helper/batch/quick_diff.py b/tools/reimplementation-helper/batch/quick_diff.py new file mode 100644 index 000000000..2e10caa40 --- /dev/null +++ b/tools/reimplementation-helper/batch/quick_diff.py @@ -0,0 +1,167 @@ +"""Compile ONE source file and diff its code against the original function, in seconds. + +usage: quick_diff.py FILE.cpp... [-q] + +Compiles each file with a DLL compile command plus /FA (no link, no reccmp), disassembles the original function +at the file's `// FUNCTION:` address straight from `_original/` with capstone, normalizes both streams (globals, +call/jump targets and esp slots become tokens) and prints a difflib ratio and a unified diff (- original, + ours). +`-q` prints the ratio only. + +This is a triage loop, not the score: it is stricter than reccmp about register names and looser about stack +offsets and constants, so confirm a 1.0000 with `reccmp_report.py --run`. Unlike reccmp it shows the *whole* +original function - reccmp cuts the original stream at the length of our function, which hides the original's +tail whenever ours is shorter. Needs capstone and a configured build directory. Do not run it while a build is +running: both write the same PDB. +""" +import difflib +import json +import os +import re +import struct +import subprocess +import sys + +import capstone + +import common + +quiet = '-q' in sys.argv +files = [os.path.abspath(f) for f in sys.argv[1:] if f != '-q'] +if not files: + sys.exit(__doc__) +ROOT = str(common.ROOT).replace(chr(92), '/') +os.chdir(ROOT) +ENV = common.build_env() +ENV['PATH'] = os.path.join(ROOT, 'MSVC1400-SP1', 'Common7', 'IDE') + os.pathsep + ENV['PATH'] +cc = json.load(open('build-RelWithDebInfo/compile_commands.json')) +base = [e for e in cc if 'OpenSHC.dll.dir' in e['command'] and '/src/OpenSHC/' in e['file'].replace(chr(92), '/')][0] +out = ROOT + '/build-RelWithDebInfo/batch/quick' +os.makedirs(out, exist_ok=True) + +d = open('_original/Stronghold Crusader.exe', 'rb').read() +pe = struct.unpack_from('= 0x80000000: + return '-' + hex(0x100000000 - v) + return 'G' if v >= 0x400000 else hex(v) + + +def orig(va): + o = off(va) + res = [] + prev = None + end = va + # function ends at first int3/padding after ret/jmp once no pending forward jump target lies beyond + maxtarget = va + for i in md.disasm(d[o:o + 20000], va): + if prev in ('ret', 'jmp') and i.address > maxtarget and (i.mnemonic in ('int3', 'nop') or i.address % 16 == 0 and i.mnemonic == 'int3'): + break + if prev in ('ret', 'jmp') and i.address > maxtarget: + break + s = i.mnemonic + ' ' + i.op_str + if i.mnemonic.startswith('j') or i.mnemonic == 'call': + try: + t = int(i.op_str, 16) + if i.mnemonic != 'call' and va <= t < va + 20000: + maxtarget = max(maxtarget, t) + s = i.mnemonic + ' L' + else: + s = i.mnemonic + ' F' + except ValueError: + pass + else: + s = re.sub(r'0x[0-9a-f]+|\b\d+\b', num, s) + s = re.sub(r'(\w+) [+] G\b', r'\1 + G', s) + if i.mnemonic == 'nop' or s.startswith('lea ') and re.match(r'lea (\w+), \[\1\]$', s) or s in ('mov edi, edi',): + prev = prev + continue + res.append(s.strip()) + prev = i.mnemonic + return res + + +def ours(f, cls, name): + cmd = base['command'] + cmd = re.sub(r'/Fo\S+', lambda m: '/Fo' + out + '/x.obj /FA /Fa' + out + '/x.asm', cmd) + cmd = re.sub(r'-c \S+$', lambda m: '-c ' + f, cmd) + r = subprocess.run(cmd, cwd=base['directory'], env=ENV, capture_output=True, text=True) + if r.returncode: + print('\n'.join(l for l in r.stdout.splitlines() if 'error' in l) or r.stdout[-500:]) + return None + txt = open(out + '/x.asm', errors='replace').read() + m = re.search(r'^(\?%s@%s@\S+) PROC.*?\n(.*?)^\1 ENDP' % (name, cls), txt, re.S | re.M) + if not m: + print('no code found for %s::%s' % (cls, name)) + return None + res = [] + for l in m.group(2).splitlines(): + l = l.split(';')[0].strip() + if not l or l.endswith(':') or re.match(r'^\w+\$ = ', l) or l.startswith('npad') or l.startswith('$') or l.startswith('DD') or l.startswith('DB') or l.startswith('_'): + continue + l = l.replace('\t', ' ') + op = l.split(' ')[0] + if op.startswith('j') and 'DWORD PTR' not in l: + l = op + (' L' if '$' in l else ' F') + elif op == 'call': + l = 'call F' + else: + l = re.sub(r'OFFSET ', '', l) + l = re.sub(r'\?[\w?$@]+', 'G', l) + l = re.sub(r'_\w+\$\[', '[', l) + l = re.sub(r'\b([0-9a-f]+)H\b', lambda m: hex(int(m.group(1), 16)), l) + l = re.sub(r'(? len(_listed) // 2: + sys.stderr.write( + "warning: the last reccmp run covers only %d of the %d functions in the build " + "list.\n Re-run with --run, or this reports on stale results.\n" + % (len(_listed) - _missing, len(_listed))) + if mode == "pct": path_filter = args[1] if len(args) > 1 else "" total = count = 0 @@ -43,6 +55,13 @@ elif mode == "save": snapshot = {e["name"]: [float(e["matching"]), common.normalized_ratio(e)] for f, e, a in common.entries(byaddr) if e} + # A snapshot of a partial run is worse than no snapshot: every function it is missing reads + # as 0.0 later, so the comparison calls the whole namespace "better" and hides any real + # regression among the noise. Refuse instead, rather than writing a file that looks fine. + listed = sum(1 for _ in common.entries(byaddr)) + if listed and len(snapshot) <= listed // 2: + sys.exit("refusing to save: the last reccmp run covers %d of the %d functions in the " + "build list.\nRe-run with --run first." % (len(snapshot), listed)) json.dump(snapshot, open(args[1], "w"), indent=0) elif mode == "cmp": diff --git a/tools/reimplementation-helper/batch/reorder_search.py b/tools/reimplementation-helper/batch/reorder_search.py new file mode 100644 index 000000000..21f20b9c8 --- /dev/null +++ b/tools/reimplementation-helper/batch/reorder_search.py @@ -0,0 +1,204 @@ +"""Hill-climb the match % by reordering independent statements. + +usage: reorder_search.py CPP-FILE FUNCTION-SUBSTRING [--pairs] [--dry] + +MSVC's register allocation is sensitive to the order in which values become +live, so reordering statements that are independent of each other can change it +without changing behaviour. The search applies one move, rebuilds, measures, +and keeps the move only if reccmp's percentage rises; anything else is reverted. +Put only the one file in cmake/openshc-sources.txt.local first, or each trial +costs a full build. + +Moves: + default permute whole runs of >=3 mutually independent statements + (reverse / rotate / counter-rotate) - 3 builds per run + --pairs swap every adjacent independent pair - 1 build per pair, much + slower on a big function but finds things runs cannot + +Two statements count as independent when neither contains a call, their +left-hand sides differ, neither left-hand side appears in the other statement, +no plain local written by one is mentioned by the other, and two writes through +the same array base are distinct named fields of the identical element. That +is deliberately conservative; verify the kept reorder by reading the diff. + +Expect a low hit rate - about one move in ten pays, and usually a fraction of a +point. The exceptions are statements that sit on a boundary, between two calls +or on a loop back-edge, where the order decides what is live in which register: +those have been worth 2 points. Run it after the structural work, not before. +""" + +import json +import re +import subprocess +import sys +from pathlib import Path + +import common # noqa: F401 (chdirs to the repo root) + +CPP, FUNC = sys.argv[1], sys.argv[2] +PAIRS = "--pairs" in sys.argv +DRY = "--dry" in sys.argv +ID = re.compile(r"[A-Za-z_]\w*") +CALL = re.compile(r"\bMACRO_CALL\w*\s*\(|\b\w+\s*\([^)]") +# a `case X:`, `default:` or plain goto label - a boundary between statements, never part of one +LABEL = re.compile(r"^(case\b.*|default\s*|[A-Za-z_]\w*\s*):$") + + +def build_and_score(): + r = subprocess.run([sys.executable, "tools/reimplementation-helper/batch/build_quiet.py"], + capture_output=True, text=True) + if "BUILD_OK" not in r.stdout: + return None + subprocess.run([sys.executable, "tools/reimplementation-helper/batch/reccmp_report.py", "--run", "pct"], + capture_output=True, text=True) + for e in json.loads(Path("reccmp/dll/diff.json").read_text())["data"]: + if e["name"].endswith(FUNC): + return float(e["matching"]) + return None + + +def statements(lines, lo, hi): + """(start, end, depth) for each statement in lines[lo:hi] at a single brace depth.""" + out, depth, i = [], 0, lo + keywords = ("for", "while", "return", "break", "continue", "goto", "case", "default") + while i < hi: + s = lines[i].strip() + d0 = depth + depth += lines[i].count("{") - lines[i].count("}") + if s.endswith(";") and d0 == depth and not s.startswith(keywords): + out.append((i, i + 1, d0)) + i += 1 + continue + if s and not s.endswith((";", "{", "}")) and d0 == depth \ + and not s.startswith(keywords) and not LABEL.match(s): + # A statement wrapped over several lines, but stop at anything that is a boundary + # rather than an operand: without this a `case N:` line is glued to the statement + # under it and the pair can then be swapped out of its own case, which strands the + # other statements of that case after a `break` where they never run. That produced + # a silent behaviour change that reccmp scored 8.9% *better*, because the dead code + # happened to leave an instruction stream closer to the original's. + j = i + while j < hi and not lines[j].strip().endswith(";"): + t = lines[j].strip() + if "{" in lines[j] or "}" in lines[j] or t.startswith(keywords) or LABEL.match(t): + j = -1 + break + j += 1 + if j != -1 and j < hi: + out.append((i, j + 1, d0)) + i = j + 1 + continue + i += 1 + return out + + +def split_assign(text): + m = re.match(r"\s*([^=;]+?)\s*=(?!=)(.*)", text, re.S) + return (None, None) if not m else (" ".join(m.group(1).split()), m.group(2)) + + +def independent(a, b): + if CALL.search(a) or CALL.search(b): + return False + la, _ = split_assign(a) + lb, _ = split_assign(b) + if la is None or lb is None or la == lb: + return False + na, nb = " ".join(a.split()), " ".join(b.split()) + if "[" in la and "[" in lb and la.split("[")[0].strip() == lb.split("[")[0].strip(): + pa, pb = la.rsplit("]", 1), lb.rsplit("]", 1) + if not (pa[0] == pb[0] and pa[1].startswith(".") and pb[1].startswith(".") and pa[1] != pb[1]): + return False + if la in nb or lb in na: + return False + for lhs, other in ((la, nb), (lb, na)): + if ID.fullmatch(lhs) and re.search(r"\b%s\b" % re.escape(lhs), other): + return False + for lhs, other_lhs in ((la, lb), (lb, la)): + if ID.fullmatch(other_lhs) and re.search(r"\b%s\b" % re.escape(other_lhs), lhs): + return False + return True + + +def text_of(lines, entry): + return "\n".join(lines[entry[0]:entry[1]]) + + +def runs(lines, st): + out, i = [], 0 + while i < len(st): + j = i + while j + 1 < len(st): + if st[j][1] != st[j + 1][0] or st[j][2] != st[j + 1][2]: + break + if not all(independent(text_of(lines, st[k]), text_of(lines, st[j + 1])) for k in range(i, j + 1)): + break + j += 1 + if j - i + 1 >= 3: + out.append((i, j)) + i = j + 1 if j > i else i + 1 + return out + + +def read(): + return Path(CPP).read_text(encoding="utf-8").split("\n") + + +def write(ls): + Path(CPP).write_text("\n".join(ls), encoding="utf-8", newline="") + + +best = build_and_score() +if best is None: + sys.exit("baseline build failed") +print("baseline %.2f%%" % (best * 100)) + +improved, rnd = True, 0 +while improved and rnd < 3: + improved, rnd = False, rnd + 1 + lines = read() + f = next(i for i, l in enumerate(lines) if "// FUNCTION:" in l) + st = statements(lines, f, len(lines)) + if PAIRS: + moves = [] + for k in range(len(st) - 1): + if st[k][1] == st[k + 1][0] and st[k][2] == st[k + 1][2] \ + and independent(text_of(lines, st[k]), text_of(lines, st[k + 1])): + moves.append((st[k][0], st[k][1], st[k + 1][0], st[k + 1][1])) + print("round %d: %d candidate swaps" % (rnd, len(moves))) + if DRY: + break + for a0, a1, b0, b1 in reversed(moves): + cur = read() + write(cur[:a0] + cur[b0:b1] + cur[a0:a1] + cur[b1:]) + sc = build_and_score() + if sc is not None and sc > best + 1e-9: + print(" keep swap L%d<->L%d %.2f -> %.2f" % (a0 + 1, b0 + 1, best * 100, sc * 100)) + best, improved = sc, True + else: + write(cur) + else: + rs = runs(lines, st) + print("round %d: %d independent runs (lengths %s)" % (rnd, len(rs), [b - a + 1 for a, b in rs])) + if DRY: + break + for a, b in reversed(rs): + lines = read() + st = statements(lines, next(i for i, l in enumerate(lines) if "// FUNCTION:" in l), len(lines)) + if b >= len(st): + continue + blocks = [lines[st[k][0]:st[k][1]] for k in range(a, b + 1)] + lo, hi, n = st[a][0], st[b][1], len(blocks) + for tag, order in (("reverse", list(reversed(range(n)))), + ("rotate", list(range(1, n)) + [0]), + ("counter-rotate", [n - 1] + list(range(n - 1)))): + cur = read() + shuffled = [line for idx in order for line in blocks[idx]] + write(cur[:lo] + shuffled + cur[hi:]) + sc = build_and_score() + if sc is not None and sc > best + 1e-9: + print(" keep %s L%d..L%d %.2f -> %.2f" % (tag, lo + 1, hi, best * 100, sc * 100)) + best, improved = sc, True + break + write(cur) +print("final %.2f%%" % (best * 100)) diff --git a/tools/reimplementation-helper/batch/scan_chains.py b/tools/reimplementation-helper/batch/scan_chains.py new file mode 100644 index 000000000..299b881b4 --- /dev/null +++ b/tools/reimplementation-helper/batch/scan_chains.py @@ -0,0 +1,48 @@ +"""List if/else-if chains that compare one expression against several constants. + +That is the shape a switch compiles from, so when scan_dispatch.py says the original has +a jump table we do not, this finds the candidates to convert. It is also a readability +report on its own: a chain of six `x == K` tests usually reads better as a switch. + +usage: + scan_chains.py [path-filter] [--min N] +""" + +import argparse +import re + +import common + +parser = argparse.ArgumentParser() +parser.add_argument("path_filter", nargs="?", default="") +parser.add_argument("--min", type=int, default=4, dest="least") +args = parser.parse_args() + +TEST = re.compile(r"(?:\}\s*)?else\s+if\s*\(\s*(?P[^()]+?)\s*==\s*[^()]+\)|" + r"^\s*if\s*\(\s*(?P[^()]+?)\s*==\s*[^()]+\)") + +total = 0 +for f in common.list_files(): + if args.path_filter not in f: + continue + lines = common.read_text(f).splitlines() + lhs_run, start, count = None, 0, 0 + + def report(): + global total + if count >= args.least: + print("%-52s line %-5d %2d branches on %s" + % (f.rsplit("/", 1)[-1][:-4], start + 1, count, lhs_run[:55])) + total += 1 + + for i, line in enumerate(lines): + m = TEST.search(line) + lhs = (m.group("lhs") or m.group("lhs2")).strip() if m else None + if lhs is not None and lhs == lhs_run: + count += 1 + continue + report() + lhs_run, start, count = (lhs, i, 1) if lhs is not None else (None, i, 0) + report() + +print("%d chain(s) with at least %d branches" % (total, args.least)) diff --git a/tools/reimplementation-helper/batch/scan_dispatch.py b/tools/reimplementation-helper/batch/scan_dispatch.py new file mode 100644 index 000000000..3ee5121b0 --- /dev/null +++ b/tools/reimplementation-helper/batch/scan_dispatch.py @@ -0,0 +1,39 @@ +"""Report functions whose dispatch form disagrees with the original. + +A jump table compiles to `jmp dword ptr [reg*4 + ]`. Counting those on each side +of the diff finds the places where the original switched on a value and we wrote an +if/else-if chain, or the other way round. Both directions have been worth several +percent, so it is worth checking before hunting through a diff by hand. + + ours > orig a switch of ours became a table the original does not have + -> try an if/else-if chain + ours < orig the original has a table we do not + -> try a switch, or check that every value has its own case label + (handing values to `default:` and re-testing them with an if drops + them out of the table) + +usage: + scan_dispatch.py [path-filter] +""" + +import sys + +import common + +path_filter = sys.argv[1] if len(sys.argv) > 1 else "" + +rows = [] +for f, e, a in common.entries(common.load_diff()): + if e is None or path_filter not in f: + continue + orig, recomp = common._asm_lines(e) + ours = sum(1 for l in recomp if "jmp dword ptr" in l) + theirs = sum(1 for l in orig if "jmp dword ptr" in l) + if ours != theirs: + rows.append((abs(ours - theirs), ours, theirs, float(e["matching"]), e["name"])) + +rows.sort(reverse=True) +print("%5s %5s %7s %s" % ("ours", "orig", "match", "function")) +for _, ours, theirs, raw, name in rows: + print("%5d %5d %6.1f%% %s" % (ours, theirs, raw * 100, name.split("::")[-1])) +print("%d function(s) where the dispatch form differs" % len(rows)) diff --git a/tools/reimplementation-helper/batch/strip_noise_comments.py b/tools/reimplementation-helper/batch/strip_noise_comments.py new file mode 100644 index 000000000..1e064b748 --- /dev/null +++ b/tools/reimplementation-helper/batch/strip_noise_comments.py @@ -0,0 +1,107 @@ +"""Remove the block comments above a reimplemented function. + +Ghidra prefixes a decompilation with one block comment per analysis complaint, plus the +provenance marker the import writes: + + /* + WARNING: Enum "MappersEnumInt": Some values do not have unique names + */ + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 + */ + +Every block comment in the run directly above a `// FUNCTION:` line is deleted, including +blocks holding hand-written notes. Comments inside a body (the string literal annotated +next to a playWAVSFX call, say) and `//` line comments are never touched. + +Dry run by default like the other rewriting scripts: read the report, then pass --apply. + +usage: + strip_noise_comments.py [path-filter] [--apply] [--show] +""" + +import re +import sys +from pathlib import Path + +import common + +FUNCTION_LINE = re.compile(r"^\s*//\s*FUNCTION:") +# a whole-line comment opener/closer, so a trailing comment on a line of code is not mistaken for one +OPEN = re.compile(r"^\s*/\*") +CLOSE = re.compile(r"\*/\s*$") + + +def content_lines(block): + """The block's text with the /* */ framing and the leading ` * ` decoration stripped.""" + text = "\n".join(block) + text = text[text.index("/*") + 2:] + text = text[:text.rindex("*/")] + out = [] + for line in text.split("\n"): + line = re.sub(r"^\s*\*(?!/)", "", line).strip() + if line: + out.append(line) + return out + + +def preceding_blocks(lines, index): + """Spans (start, end) of the block comments immediately above lines[index], outermost first.""" + spans = [] + j = index - 1 + while j >= 0: + if not CLOSE.search(lines[j]) or lines[j].strip().startswith("//"): + break + k = j + while k >= 0 and not OPEN.match(lines[k]): + k -= 1 + if k < 0: + break + spans.append((k, j)) + j = k - 1 + spans.reverse() + return spans + + +def main(): + path_filter = "" + apply = False + show = False + for arg in sys.argv[1:]: + if arg == "--apply": + apply = True + elif arg == "--show": + show = True + else: + path_filter = arg + + files = sorted(p.as_posix() for p in Path("src/OpenSHC").rglob("*.cpp")) + removed = touched = 0 + for f in files: + if path_filter not in f: + continue + lines = common.read_text(f).replace("\r\n", "\n").split("\n") + drop = set() + n = 0 + for i, line in enumerate(lines): + if not FUNCTION_LINE.match(line): + continue + for start, end in preceding_blocks(lines, i): + drop.update(range(start, end + 1)) + n += 1 + if show: + print("%s:%d | %s" % (f, start + 1, + " / ".join(content_lines(lines[start:end + 1]))[:120])) + if not n: + continue + removed += n + touched += 1 + print("%-60s -%d" % (f[len("src/OpenSHC/"):], n)) + if apply: + common.write_text(f, "\n".join(l for i, l in enumerate(lines) if i not in drop)) + + print("%d block comment(s) in %d file(s)%s" + % (removed, touched, "" if apply else " (dry run, pass --apply)")) + + +main() diff --git a/tools/reimplementation-helper/batch/test_deparen.py b/tools/reimplementation-helper/batch/test_deparen.py new file mode 100644 index 000000000..9a62a3845 --- /dev/null +++ b/tools/reimplementation-helper/batch/test_deparen.py @@ -0,0 +1,47 @@ +"""Precedence tests for deparen.py. + +Every case here is one where the brackets are load-bearing, or where an earlier version of +the script got it wrong. Run this after touching the precedence table. + +usage: + test_deparen.py +""" + +import deparen + +CASES = [ + # || inside && keeps its brackets (an earlier version dropped them and silently + # changed the expression) + ("(a != 0 || b != 0) && (x & 0x100) == 0", + "(a != 0 || b != 0) && (x & 0x100) == 0"), + # & binds looser than ==, so that group stays + ("((x & 0x100) == 0 || (y & 0x100) == 0)", + "(x & 0x100) == 0 || (y & 0x100) == 0"), + # a plain over-bracketed && chain flattens + ("(((a == 1) && (b == 2)) && (c == 3))", "a == 1 && b == 2 && c == 3"), + # an assignment inside a condition keeps its group + ("(a == 1) && ((v = f(x), v != 0))", "a == 1 && (v = f(x), v != 0)"), + # && inside || is legal to unwrap but clearer kept + ("(a == 1 && b == 2) || c == 3", "(a == 1 && b == 2) || c == 3"), + # bitwise groups stay whatever joins them + ("(a & 7) != 0 && (b | 1) == 3", "(a & 7) != 0 && (b | 1) == 3"), + # a lone comparison unwraps + ("(a == 1)", "a == 1"), + # nested || of the same operator flattens + ("((a == 1 || (b == 2)) || c == 3)", "a == 1 || b == 2 || c == 3"), +] + +if __name__ == "__main__": + failures = 0 + for src, want in CASES: + outer = src + while deparen.is_group(outer) and deparen.rank(outer[1:-1]) > 1: + outer = outer[1:-1].strip() + got = deparen.simplify(outer) + ok = got == want + failures += not ok + print("%-4s %s" % ("ok" if ok else "FAIL", src)) + if not ok: + print(" got %s\n want %s" % (got, want)) + print("\n%d/%d passed" % (len(CASES) - failures, len(CASES))) + raise SystemExit(1 if failures else 0) diff --git a/tools/reimplementation-helper/batch/test_undiv.py b/tools/reimplementation-helper/batch/test_undiv.py new file mode 100644 index 000000000..b58fddbf7 --- /dev/null +++ b/tools/reimplementation-helper/batch/test_undiv.py @@ -0,0 +1,45 @@ +"""Cases for undiv.py. + +The rewrites here are the shapes actually found in the decompiled sources, plus the +near-misses that must be left alone: a mismatched shift, a mask that is not 2^k - 1, and a +bias taken from a different variable than the one being divided. + +usage: + test_undiv.py +""" + +import undiv + +CASES = [ + # the plain form + ("v = (x + (x >> 0x1f & 7U)) >> 3;", "v = x / 8;"), + # the sum wrapped in a signed cast, which is where the shift then sits + ("v = (int)(x + (x >> 0x1f & 0xfU)) >> 4;", "v = x / 16;"), + # a cast on the dividend inside the bias as well as outside it + ("v = (int)((int)a->b + ((int)a->b >> 0x1f & 7U)) >> 3;", "v = a->b / 8;"), + # a wide mask + ("v = ((int)(r + ((int)r >> 0x1f & 0x1ffU)) >> 9) + k;", "v = (r / 512) + k;"), + # two independent divisions in one expression + ("v = ((x + (x >> 0x1f & 7U)) >> 3) - ((y + (y >> 0x1f & 7U)) >> 3);", + "v = (x / 8) - (y / 8);"), + # shift does not match the mask: not this idiom, leave it + ("v = (x + (x >> 0x1f & 7U)) >> 2;", "v = (x + (x >> 0x1f & 7U)) >> 2;"), + # mask is not 2^k - 1 + ("v = (x + (x >> 0x1f & 5U)) >> 3;", "v = (x + (x >> 0x1f & 5U)) >> 3;"), + # the bias is taken from a different variable + ("v = (x + (y >> 0x1f & 7U)) >> 3;", "v = (x + (y >> 0x1f & 7U)) >> 3;"), + # an unbiased shift is an unsigned division or a real shift; not ours to touch + ("v = x >> 3;", "v = x >> 3;"), +] + +if __name__ == "__main__": + failures = 0 + for src, want in CASES: + got, _ = undiv.process(src) + ok = got == want + failures += not ok + print("%-4s %s" % ("ok" if ok else "FAIL", src)) + if not ok: + print(" got %s\n want %s" % (got, want)) + print("\n%d/%d passed" % (len(CASES) - failures, len(CASES))) + raise SystemExit(1 if failures else 0) diff --git a/tools/reimplementation-helper/batch/test_unmod.py b/tools/reimplementation-helper/batch/test_unmod.py new file mode 100644 index 000000000..0d96ee01f --- /dev/null +++ b/tools/reimplementation-helper/batch/test_unmod.py @@ -0,0 +1,60 @@ +"""Cases for unmod.py. + +usage: + test_unmod.py +""" + +import unmod + +PLAIN = """ uint v = x & 0x8000000f; + if ((int)v < 0) { + v = (v - 1 | 0xfffffff0) + 1; + } +""" +SUM = """ uVar9 = (int)a->b + 4U & 0x80000007; + if ((int)uVar9 < 0) { + uVar9 = (uVar9 - 1 | 0xfffffff8) + 1; + } +""" +FIELD = """ this->u[i].r = this->u[i].fixedRng & 0x80000003; + if ((int)this->u[i].r < 0) { + this->u[i].r = (this->u[i].r - 1 | 0xfffffffc) + 1; + } +""" +# the repair constant does not complement the mask: not this idiom +BAD_COMP = """ uint v = x & 0x8000000f; + if ((int)v < 0) { + v = (v - 1 | 0xfffffff8) + 1; + } +""" +# the repair is applied to a different variable +BAD_VAR = """ uint v = x & 0x8000000f; + if ((int)w < 0) { + w = (w - 1 | 0xfffffff0) + 1; + } +""" +# a bare mask, with no repair, is not a signed modulo +BARE = " uint v = x & 0xf;\n" + +CASES = [ + # the dividend gets a signed cast: the repair the compiler emitted only exists for a + # signed operand, so an unsigned `%` would compile to a bare `and` and stop matching + (PLAIN, " uint v = (int)x % 16;\n", 1), + (SUM, " uVar9 = ((int)a->b + 4) % 8;\n", 1), + (FIELD, " this->u[i].r = (int)this->u[i].fixedRng % 4;\n", 1), + (BAD_COMP, BAD_COMP, 0), + (BAD_VAR, BAD_VAR, 0), + (BARE, BARE, 0), +] + +if __name__ == "__main__": + failures = 0 + for src, want, want_n in CASES: + got, n = unmod.process(src) + ok = got == want and n == want_n + failures += not ok + print("%-4s %s" % ("ok" if ok else "FAIL", src.strip().split("\n")[0])) + if not ok: + print(" got %r (%d)\n want %r (%d)" % (got, n, want, want_n)) + print("\n%d/%d passed" % (len(CASES) - failures, len(CASES))) + raise SystemExit(1 if failures else 0) diff --git a/tools/reimplementation-helper/batch/test_unptr.py b/tools/reimplementation-helper/batch/test_unptr.py new file mode 100644 index 000000000..72ca429a8 --- /dev/null +++ b/tools/reimplementation-helper/batch/test_unptr.py @@ -0,0 +1,70 @@ +"""Cases for unptr.py. + +usage: + test_unptr.py +""" + +import unptr + +CASES = [ + # the ordinary increment + (""" piVar1 = &this->units[i].attackedBy; + *piVar1 = *piVar1 + 1; +""", + " this->units[i].attackedBy = this->units[i].attackedBy + 1;\n", 1), + # a wrapped lvalue, which clang-format produces for the long ones + (""" piVar1 = &DAT_GameState::instance.playerDataArray[p] + .totalAttackTroops; + *piVar1 = *piVar1 + 1; +""", + " DAT_GameState::instance.playerDataArray[p].totalAttackTroops = " + "DAT_GameState::instance.playerDataArray[p].totalAttackTroops + 1;\n", 1), + # declared on the spot: the type prefix goes with the pointer, or it is left stranded in + # front of the lvalue and the file stops compiling + (""" char* pcVar3 = &a.moats[t].someCountDown; + *pcVar3 = *pcVar3 + -0x14; +""", + " a.moats[t].someCountDown = a.moats[t].someCountDown + -0x14;\n", 1), + # something other than a plain increment on the right + (""" psVar4 = &a.b; + *psVar4 = *psVar4 - c * 2; +""", + " a.b = a.b - c * 2;\n", 1), + # set up here, dereferenced further down: the index could change in between, so leave it + (""" psVar4 = &this->units[k].field97; + if (this->units[k].field97 > 0) { + *psVar4 = *psVar4 + 1; + } +""", + """ psVar4 = &this->units[k].field97; + if (this->units[k].field97 > 0) { + *psVar4 = *psVar4 + 1; + } +""", 0), + # a store through a different pointer than the one just assigned + (""" piVar1 = &a.b; + *piVar2 = *piVar2 + 1; +""", + """ piVar1 = &a.b; + *piVar2 = *piVar2 + 1; +""", 0), + # a plain pointer that is not a decompiler name is none of our business + (""" rowPtr = &a.b; + *rowPtr = *rowPtr + 1; +""", + """ rowPtr = &a.b; + *rowPtr = *rowPtr + 1; +""", 0), +] + +if __name__ == "__main__": + failures = 0 + for src, want, want_n in CASES: + got, n = unptr.process(src) + ok = got == want and n == want_n + failures += not ok + print("%-4s %s" % ("ok" if ok else "FAIL", src.strip().split("\n")[0])) + if not ok: + print(" got %r (%d)\n want %r (%d)" % (got, n, want, want_n)) + print("\n%d/%d passed" % (len(CASES) - failures, len(CASES))) + raise SystemExit(1 if failures else 0) diff --git a/tools/reimplementation-helper/batch/try_styles.py b/tools/reimplementation-helper/batch/try_styles.py new file mode 100644 index 000000000..4a44d217f --- /dev/null +++ b/tools/reimplementation-helper/batch/try_styles.py @@ -0,0 +1,121 @@ +"""Build and measure several source styles of one function, then keep the best. + +Whether a given style matches better is not predictable: naming a repeatedly read field +gained 18% in one function and lost 12% in another, and reusing a pointer for two rows +helped one function and hurt its near-identical neighbour. So write the candidates out and +measure them instead of arguing about them. + +Put each complete .cpp in + build-RelWithDebInfo/batch/variants//