diff --git a/cmake/compiler-flags-gl.txt b/cmake/compiler-flags-gl.txt index 0e2e4f053..bc44f2052 100644 --- a/cmake/compiler-flags-gl.txt +++ b/cmake/compiler-flags-gl.txt @@ -53,4 +53,6 @@ src/OpenSHC/Map/Buildings/BuildingsState/applyVersionUpgradeAccessibilityRecompu src/OpenSHC/Map/Buildings/BuildingsState/recomputeAccessibilityForAllBuildings.cpp src/OpenSHC/Map/Buildings/BuildingsState/getResourceSpace.cpp src/OpenSHC/Synchrony/GameSynchronyState/processSyncPacket.cpp -src/OpenSHC/Synchrony/GameSynchronyState/translateMultiplayerIDsIntoPlayerIDs.cpp \ No newline at end of file +src/OpenSHC/Synchrony/GameSynchronyState/translateMultiplayerIDsIntoPlayerIDs.cpp +src/OpenSHC/Map/Buildings/BuildingsState/processResourceLoss.cpp +src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachBuildingPerimeter.cpp \ No newline at end of file diff --git a/src/OpenSHC/AI/AIVState/aiPlaceAIVBuilding.cpp b/src/OpenSHC/AI/AIVState/aiPlaceAIVBuilding.cpp index 5e947a8bf..194e8a59b 100644 --- a/src/OpenSHC/AI/AIVState/aiPlaceAIVBuilding.cpp +++ b/src/OpenSHC/AI/AIVState/aiPlaceAIVBuilding.cpp @@ -297,7 +297,7 @@ namespace AI { orientation); int const placedID = DAT_TileMapState::instance.placedBuildingID; if (!DAT_TileMapState::instance.buildingPlacementFail) { - DAT_BuildingsState::instance.buildings[placedID].field202_0x2c8 = 1; + DAT_BuildingsState::instance.buildings[placedID].field201_0x2c8 = 1; MACRO_CALL_MEMBER(AICState_Func::setupWorkshopProductionType, DAT_AICState::ptr)(playerID, placedID); } if (!DAT_TileMapState::instance.buildingPlacementFail) { diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachAdjacentTile.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachAdjacentTile.cpp new file mode 100644 index 000000000..6bd43dfcf --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachAdjacentTile.cpp @@ -0,0 +1,48 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +#include + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x004105F0 + BOOLEnum BuildingsState::canUnitReachAdjacentTile(int param_1, int param_2) + { + int const row = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[param_1]; + int const unitArea + = (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[param_2].tile]; + int const height = DAT_TileMapState::instance.HeightLayer[param_1]; + if (MACRO_CALL_MEMBER(Units::UnitsState_Func::selectionContainsOnlyArabAssassins, DAT_UnitsState::ptr)() + != FALSE) { + return FALSE; + } + for (int direction = 0; direction < 8; ++direction) { + int const area + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_TileMapState::instance.directionTranslationMatrix[row][direction] + + param_1]; + // The original compares the height of param_1 with itself, not with the neighbouring tile. + if (abs(height - DAT_TileMapState::instance.HeightLayer[param_1]) < 16 && area != 0 + && MACRO_CALL_MEMBER( + Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_UnitsState::instance.units[param_2].owner, unitArea, area, + MACRO_CALL_MEMBER(Units::UnitsState_Func::canAUnitClimb, DAT_UnitsState::ptr)()) + != 0) { + return TRUE; + } + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachBuildingPerimeter.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachBuildingPerimeter.cpp new file mode 100644 index 000000000..672f573b8 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/canUnitReachBuildingPerimeter.cpp @@ -0,0 +1,72 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +#include + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x00410440 + BOOLEnum BuildingsState::canUnitReachBuildingPerimeter(int buildingID, int unitID) + { + if (buildingID == 0 || buildingID >= 2000) { + return FALSE; + } + int const unitArea + = (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile]; + int const size = this->buildings[buildingID].widthOrHeight; + int const buildingHeight + = DAT_TileMapState::instance.DefaultHeightLayer[DAT_BuildingsState::instance.buildings[buildingID] + .currentTilePositionAdjusted]; + int const tileCount = DAT_BuildingDefinedData::instance.BuildingAccessibleTilesCount[size]; + int onlyAssassins = 0; + if (MACRO_CALL_MEMBER(Units::UnitsState_Func::selectionContainsOnlyArabAssassins, DAT_UnitsState::ptr)() + != FALSE) { + onlyAssassins = 1; + } + for (int i = 0; i < tileCount; ++i) { + MACRO_CALL_MEMBER(BuildingsState_Func::setupNextCandidateLocationComputeOffsets2, this)(size, 1, i, 0); + int const tile = DAT_ViewportRenderState::instance + .translationMatrix[this->buildings[buildingID].y + this->DAT_TempYOffset] + .addXgetTile + + this->buildings[buildingID].x + this->DAT_TempXOffset; + int const area = (short)DAT_TileMapState::instance.PathConnectionLayer[tile]; + int tileHeight = DAT_TileMapState::instance.HeightLayer[tile]; + if (DAT_TileMapState::instance.BuildingLayer[tile] != 0) { + tileHeight += MACRO_CALL_MEMBER(BuildingsState_Func::getBuildingHeightForBuildingID, + DAT_BuildingsState::ptr)(DAT_TileMapState::instance.BuildingLayer[tile]); + } + if (abs(buildingHeight - tileHeight) >= 16 || area == 0) { + continue; + } + int reachable; + if (onlyAssassins == 1) { + reachable + = MACRO_CALL_MEMBER(Navigation::PathFindingState_Func::calculateCanReachUsingCachedAreaLogic, + DAT_PathFindingState::ptr)(DAT_UnitsState::instance.units[unitID].tile, tile); + } else { + reachable = MACRO_CALL_MEMBER( + Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_UnitsState::instance.units[unitID].owner, unitArea, area, + MACRO_CALL_MEMBER(Units::UnitsState_Func::canAUnitClimb, DAT_UnitsState::ptr)()); + } + if (reachable != 0) { + return TRUE; + } + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/countBuildingsForPlayer.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/countBuildingsForPlayer.cpp index e83869f67..994ba8785 100644 --- a/src/OpenSHC/Map/Buildings/BuildingsState/countBuildingsForPlayer.cpp +++ b/src/OpenSHC/Map/Buildings/BuildingsState/countBuildingsForPlayer.cpp @@ -14,7 +14,7 @@ namespace Map { if (this->buildings[buildingID].logicalState == BLS_NORMAL && this->buildings[buildingID].owner == playerID && this->buildings[buildingID].buildingType == buildingType - && (includeBool == 0 || this->buildings[buildingID].field202_0x2c8 == 0)) { + && (includeBool == 0 || this->buildings[buildingID].field201_0x2c8 == 0)) { ++count; } } diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/countFarms.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/countFarms.cpp index fe869da07..b8d6940f4 100644 --- a/src/OpenSHC/Map/Buildings/BuildingsState/countFarms.cpp +++ b/src/OpenSHC/Map/Buildings/BuildingsState/countFarms.cpp @@ -17,7 +17,7 @@ namespace Map { && (this->buildings[buildingID].buildingType == BT_WHEATFARM || this->buildings[buildingID].buildingType == BT_APPLEFARM || this->buildings[buildingID].buildingType == BT_DAIRYFARM) - && (param_2 == 0 || this->buildings[buildingID].field202_0x2c8 == 0)) { + && (param_2 == 0 || this->buildings[buildingID].field201_0x2c8 == 0)) { ++count; } } diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/countPlayerResources.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/countPlayerResources.cpp new file mode 100644 index 000000000..c2c0bc27a --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/countPlayerResources.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + using OpenSHC::Map::Buildings::BuildingLogicalState; + using OpenSHC::Map::Buildings::BuildingType; + + // FUNCTION: STRONGHOLDCRUSADER 0x0040C300 + void BuildingsState::countPlayerResources(int playerID) + { + int gold + = DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD]; + + // Reset the stored resources and recount them from the storage buildings, gold is kept + for (int i = 0; i < 25; ++i) { + if (i != OpenSHC::Game::Resources::RT_GOLD) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[i] = 0; + } + } + for (int i = 1; i < this->maxBuildingsCount; ++i) { + if (this->buildings[i].logicalState != BLS_NORMAL || this->buildings[i].owner != playerID) { + continue; + } + if (this->buildings[i].buildingType != BT_STOCKPILE && this->buildings[i].buildingType != BT_GRANARY + && this->buildings[i].buildingType != BT_ARMORY) { + continue; + } + if (this->buildings[i].buildingType == BT_STOCKPILE) { + for (int r = OpenSHC::Game::Resources::RT_WOOD; r <= OpenSHC::Game::Resources::RT_FLOUR; ++r) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[r] + += this->buildings[i].resources[r]; + } + } else if (this->buildings[i].buildingType == BT_GRANARY) { + for (int r = OpenSHC::Game::Resources::RT_BREAD; r <= OpenSHC::Game::Resources::RT_APPLE; ++r) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[r] + += this->buildings[i].resources[r]; + } + } else if (this->buildings[i].buildingType == BT_ARMORY) { + for (int r = OpenSHC::Game::Resources::RT_BOW; r < 25; ++r) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[r] + += this->buildings[i].resources[r]; + } + } + } + DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD] + = gold; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/extinguishBuildingFire.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/extinguishBuildingFire.cpp new file mode 100644 index 000000000..aa162dd7c --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/extinguishBuildingFire.cpp @@ -0,0 +1,59 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x004109F0 + void BuildingsState::extinguishBuildingFire(int buildingID) + { + if (this->buildings[buildingID].fireDuration == 0) { + return; + } + int const x = this->buildings[buildingID].x; + int const y = this->buildings[buildingID].y; + int size = this->buildings[buildingID].widthOrHeight; + this->buildings[buildingID].fireDuration = 0; + this->buildings[buildingID].cooldownTimer = 2000; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WHEATFARM) { + size = 9; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_HOPFARM) { + size = 9; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DAIRYFARM) { + size = 10; + } else if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APPLEFARM) { + size = 11; + } + int tile = 0; + do { + MACRO_CALL_MEMBER(TileMapState_Func::getBuildingSizeIndexMappingData, DAT_TileMapState::ptr)( + tile, size); + MACRO_CALL_MEMBER(Entities::EntityState_Func::updateAllFireEntitiesAtTile, DAT_EntityState::ptr)( + DAT_ViewportRenderState::instance.translationMatrix[y + DAT_TileMapState::instance.buildingY] + .addXgetTile + + DAT_TileMapState::instance.buildingX + x); + ++tile; + } while (tile < DAT_TileMapState::instance.constructionTileCount); + int const tileCount = DAT_BuildingDefinedData::instance.BuildingAccessibleTilesCount[size]; + for (int try_ = 0; try_ < tileCount; ++try_) { + MACRO_CALL_MEMBER(BuildingsState_Func::setupBuildingEntrancesOffset, this)(size, 1, try_, 0); + int const rowTile + = DAT_ViewportRenderState::instance.translationMatrix[this->DAT_TempYOffset + y].addXgetTile + x; + MACRO_CALL_MEMBER(Entities::EntityState_Func::updateAllFireEntitiesAtTile, DAT_EntityState::ptr)( + rowTile + this->DAT_TempXOffset); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/findClosestReachableAlliedBuilding.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/findClosestReachableAlliedBuilding.cpp new file mode 100644 index 000000000..2699a4863 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/findClosestReachableAlliedBuilding.cpp @@ -0,0 +1,64 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x00410B10 + int BuildingsState::findClosestReachableAlliedBuilding(int unitID) + { + int closestBuildingID = 0; + int closestDistance = 1000; + int const fromArea + = (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile]; + for (int buildingID = 1; buildingID < this->maxBuildingsCount; ++buildingID) { + if (this->buildings[buildingID].logicalState == 0 + || this->buildings[buildingID].logicalState == BLS_REMOVE) { + continue; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[this->buildings[buildingID].owner] + != DAT_GameState::instance.mapAndTime.playerTeams[DAT_UnitsState::instance.units[unitID].owner]) { + continue; + } + if (this->buildings[buildingID].fireDuration == 0) { + continue; + } + MACRO_CALL_MEMBER(Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[unitID].x, + DAT_UnitsState::instance.units[unitID].y, this->buildings[buildingID].buildingEntryX, + this->buildings[buildingID].buildingEntryY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh >= closestDistance) { + continue; + } + int const tile + = DAT_ViewportRenderState::instance.translationMatrix[this->buildings[buildingID].buildingEntryY] + .addXgetTile + + this->buildings[buildingID].buildingEntryX; + if (MACRO_CALL_MEMBER(Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_UnitsState::instance.units[unitID].owner, fromArea, + (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + != 0) { + closestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + closestBuildingID = buildingID; + } + } + if (closestBuildingID != 0) { + return closestBuildingID; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/findFreeCathedralAssemblyTile.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/findFreeCathedralAssemblyTile.cpp new file mode 100644 index 000000000..f0ed34375 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/findFreeCathedralAssemblyTile.cpp @@ -0,0 +1,57 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040E610 + BOOLEnum BuildingsState::findFreeCathedralAssemblyTile(int playerID, int unitID) + { + if (DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[3].x != 0) { + int const assemblyX + = DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[3].x; + int const assemblyY + = DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[3].y; + for (int i = (short)DAT_GameState::instance.playerDataArray[playerID].someCount30; i < 49; ++i) { + // The original reads the fixed offset [3] on every iteration instead of offset [i]. + int const x = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[3].x + assemblyX; + int const y = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[3].y + assemblyY; + int const tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + int const occupantID = DAT_TileMapState::instance.UnitLayer[tile]; + if (occupantID != 0 && occupantID != unitID + && DAT_UnitsState::instance.units[unitID].movementRelated == 8) { + continue; + } + if (MACRO_CALL_MEMBER( + Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + != 0) { + this->DAT_TempXOffset = x; + this->DAT_TempYOffset = y; + if (x == DAT_UnitsState::instance.units[unitID].x + && y == DAT_UnitsState::instance.units[unitID].y) { + return FALSE; + } + return TRUE; + } + } + return FALSE; + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/findFreeEngineerAssemblyTile.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/findFreeEngineerAssemblyTile.cpp new file mode 100644 index 000000000..2c5acb0c3 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/findFreeEngineerAssemblyTile.cpp @@ -0,0 +1,94 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040E120 + int BuildingsState::findFreeEngineerAssemblyTile(int playerID, int unitID) + { + int const laddermenCount = (short)DAT_GameState::instance.playerDataArray[playerID].someCount28; + int index = (int)DAT_GameState::instance.playerDataArray[playerID].someCount27 - laddermenCount; + int isLadderman = 0; + int assemblyIndex = 0; + if (DAT_UnitsState::instance.units[unitID].unitType == Units::UT_E_LADDER) { + isLadderman = 1; + assemblyIndex = 1; + index = laddermenCount; + } + if (DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[assemblyIndex].x != 0) { + int const assemblyX + = DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[assemblyIndex].x; + int const assemblyY + = DAT_GameState::instance.playerDataArray[playerID].specialBuildingAssemblyPoints[assemblyIndex].y; + for (int i = index; i < 49; ++i) { + int const x = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[i].x + assemblyX; + int const y = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[i].y + assemblyY; + int const tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + int const occupantID = DAT_TileMapState::instance.UnitLayer[tile]; + if (occupantID != 0 && occupantID != unitID + && DAT_UnitsState::instance.units[unitID].movementRelated == 8) { + continue; + } + if (MACRO_CALL_MEMBER( + Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + != 0) { + this->DAT_TempXOffset = x; + this->DAT_TempYOffset = y; + if (x == DAT_UnitsState::instance.units[unitID].x + && y == DAT_UnitsState::instance.units[unitID].y) { + return 0; + } + return 1; + } + } + return 0; + } + for (int i = index; i < 25; ++i) { + int x; + int y; + if (isLadderman != 0) { + x = DAT_GameState::instance.playerDataArray[playerID].engineersParadegroundLocations[24 - i].x; + y = DAT_GameState::instance.playerDataArray[playerID].engineersParadegroundLocations[24 - i].y; + } else { + x = DAT_GameState::instance.playerDataArray[playerID].engineersParadegroundLocations[i].x; + y = DAT_GameState::instance.playerDataArray[playerID].engineersParadegroundLocations[i].y; + } + if ((uint)x > 399 || (uint)y > 399 + || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + continue; + } + int const occupantID + = DAT_TileMapState::instance + .UnitLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x]; + if (occupantID != 0 && occupantID != unitID + && DAT_UnitsState::instance.units[unitID].movementRelated == 8) { + continue; + } + this->DAT_TempXOffset = x; + this->DAT_TempYOffset = y; + if (x == DAT_UnitsState::instance.units[unitID].x && y == DAT_UnitsState::instance.units[unitID].y) { + return 0; + } + return 1; + } + return 0; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/getPriceForDisbandedUnitType.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/getPriceForDisbandedUnitType.cpp new file mode 100644 index 000000000..6f449fd08 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/getPriceForDisbandedUnitType.cpp @@ -0,0 +1,77 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040C800 + void BuildingsState::getPriceForDisbandedUnitType(UnitType unitType, int* outPrice) + { + switch (unitType) { + case Units::UT_E_ARCHER: + *outPrice = 12; + return; + case Units::UT_E_SPEAR: + *outPrice = 8; + return; + case Units::UT_E_PIKE: + *outPrice = 20; + return; + case Units::UT_E_MACE: + *outPrice = 20; + return; + case Units::UT_E_XBOW: + *outPrice = 20; + return; + case Units::UT_E_SWORD: + *outPrice = 40; + return; + case Units::UT_E_KNIGHT: + *outPrice = 40; + return; + case Units::UT_E_LADDER: + *outPrice = 1; + return; + case Units::UT_E_ENGINEER: + *outPrice = 30; + return; + case Units::UT_E_MONK: + *outPrice = 10; + return; + case Units::UT_TUNNELER: + *outPrice = 20; + return; + case Units::UT_S_CATAPULT: + *outPrice = this->buildingCosts[BT_CATAPULT].requiredGold; + return; + case Units::UT_S_TREBUCHET: + *outPrice = this->buildingCosts[BT_TREBUCHET].requiredGold; + return; + case Units::UT_S_MANGONEL: + *outPrice = this->buildingCosts[BT_MANGONEL].requiredGold; + return; + case Units::UT_S_BALLISTA: + *outPrice = this->buildingCosts[BT_BALLISTA].requiredGold; + return; + case Units::UT_S_FBALLISTA: + *outPrice = this->buildingCosts[BT_FIREBALLISTA].requiredGold; + return; + case Units::UT_S_SHIELD: + *outPrice = this->buildingCosts[BT_SHIELD].requiredGold; + return; + // the original pairs the tower with the battering ram's cost and vice versa + case Units::UT_S_TOWER: + *outPrice = this->buildingCosts[BT_BATTERINGRAM].requiredGold; + return; + case Units::UT_S_BATTERINGRAM: + *outPrice = this->buildingCosts[BT_SIEGETOWER].requiredGold; + return; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/growWheat.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/growWheat.cpp new file mode 100644 index 000000000..12129ed99 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/growWheat.cpp @@ -0,0 +1,84 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040CC30 + void BuildingsState::growWheat(int buildingID) + { + // The damage layer holds the growth stage of the wheat on the field tiles. + // Not all stage counters are used, the compiler removes those. + int empty = 0; + int seeded = 0; + int stage2To4 = 0; + int stage5To7 = 0; + int stage8To10 = 0; + int growing = 0; + int stage101 = 0; + int stage102 = 0; + int stage103To119 = 0; + int stage120 = 0; + int stage121 = 0; + for (int i = 0; i < 36; ++i) { + int tile = this->buildings[buildingID].tileRefs[i]; + if ((char)DAT_TileMapState::instance.DamageLayer[tile] >= 2 + && (char)DAT_TileMapState::instance.DamageLayer[tile] < 103) { + ++DAT_TileMapState::instance.DamageLayer[tile]; + } + char stage = DAT_TileMapState::instance.DamageLayer[tile]; + if (stage < 1) { + ++empty; + } else if (stage < 2) { + ++seeded; + } else if (stage < 5) { + ++stage2To4; + } else if (stage < 8) { + ++stage5To7; + } else if (stage < 11) { + ++stage8To10; + } else if (stage < 101) { + ++growing; + } else if (stage < 102) { + ++stage101; + } else if (stage < 103) { + ++stage102; + } else if (stage < 120) { + ++stage103To119; + } else if (stage == 120) { + ++stage120; + } else if (stage == 121) { + ++stage121; + } + } + + if (stage121 >= 4) { + this->buildings[buildingID].farmGrowState = 8; + return; + } + if (growing >= 12 || (growing != 0 && stage120 != 0)) { + this->buildings[buildingID].farmGrowState = 6; + return; + } + if (stage121 != 0) { + this->buildings[buildingID].farmGrowState = 8; + return; + } + if (empty != 0) { + this->buildings[buildingID].farmGrowState = 3; + } else if (stage120 != 0) { + this->buildings[buildingID].farmGrowState = 3; + } else if (stage102 != 0) { + this->buildings[buildingID].farmGrowState = 3; + } else if (stage103To119 != 0) { + this->buildings[buildingID].farmGrowState = 3; + } else { + this->buildings[buildingID].farmGrowState = seeded != 0 ? 5 : 2; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingEntranceFlagForOrientation.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingEntranceFlagForOrientation.cpp index 0c345776c..82965409c 100644 --- a/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingEntranceFlagForOrientation.cpp +++ b/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingEntranceFlagForOrientation.cpp @@ -11,19 +11,19 @@ namespace Map { BOOLEnum BuildingsState::hasBuildingEntranceFlagForOrientation(int buildingID) { if (DAT_TileMapState::instance.mapOrientation == 0) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[1]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[1]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 2) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[2]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[2]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 4) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[3]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[3]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 6) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[0]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[0]) { return TRUE; } } diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingExitFlagForOrientation.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingExitFlagForOrientation.cpp index 33ba3d398..0a074b0f3 100644 --- a/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingExitFlagForOrientation.cpp +++ b/src/OpenSHC/Map/Buildings/BuildingsState/hasBuildingExitFlagForOrientation.cpp @@ -11,19 +11,19 @@ namespace Map { BOOLEnum BuildingsState::hasBuildingExitFlagForOrientation(int buildingID) { if (DAT_TileMapState::instance.mapOrientation == 0) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[2]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[2]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 2) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[3]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[3]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 4) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[0]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[0]) { return TRUE; } } else if (DAT_TileMapState::instance.mapOrientation == 6) { - if (DAT_BuildingsState::instance.buildings[buildingID].field162_0x280[1]) { + if (DAT_BuildingsState::instance.buildings[buildingID].field161_0x280[1]) { return TRUE; } } diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/initializeGatePathfindingForOwner.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/initializeGatePathfindingForOwner.cpp index 0216eb9bc..71d34cdf1 100644 --- a/src/OpenSHC/Map/Buildings/BuildingsState/initializeGatePathfindingForOwner.cpp +++ b/src/OpenSHC/Map/Buildings/BuildingsState/initializeGatePathfindingForOwner.cpp @@ -18,7 +18,7 @@ namespace Map { && DAT_BuildingsState::instance.buildings[buildingID].owner == param_1 && (DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSELARGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSESMALL) - && DAT_BuildingsState::instance.buildings[buildingID].field201_0x2c6 == 0) { + && DAT_BuildingsState::instance.buildings[buildingID].field200_0x2c6 == 0) { DAT_PathFindingState::instance .climbData[DAT_BuildingsState::instance.buildings[buildingID].laddermanDataID] .isRecognizedByPathfinding = 1; diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/isSpaceAvailableAtUnitRallyPoint.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/isSpaceAvailableAtUnitRallyPoint.cpp new file mode 100644 index 000000000..10b9ecefa --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/isSpaceAvailableAtUnitRallyPoint.cpp @@ -0,0 +1,114 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.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_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040D6E0 + BOOLEnum BuildingsState::isSpaceAvailableAtUnitRallyPoint(int playerID, int group, int unitID) + { + int const requestedGroup = group; + if (DAT_GameSynchronyState::instance.currentGameMode != 0 + && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1 + && DAT_GameSynchronyState::instance.currentAIArray[playerID] != 0 + && DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 2) { + int const keepID = DAT_GameState::instance.playerDataArray[playerID].keep.id; + if (keepID == 0) { + return FALSE; + } + this->DAT_TempXOffset = DAT_BuildingsState::instance.buildings[keepID].someX; + this->DAT_TempYOffset = DAT_BuildingsState::instance.buildings[keepID].someY; + return TRUE; + } + if (group == 6) { + group = 5; + } + int offset = DAT_GameState::instance.playerDataArray[playerID].rallySearchOffsetsUnk[group]; + if (DAT_GameState::instance.playerDataArray[playerID].barracksAssemblyPoints[requestedGroup].x != 0) { + if (requestedGroup == 6) { + offset = DAT_GameState::instance.playerDataArray[playerID].rallySearchOffset; + group = requestedGroup; + } else if (requestedGroup == 5) { + offset -= DAT_GameState::instance.playerDataArray[playerID].rallySearchOffset; + } + int const assemblyX = DAT_GameState::instance.playerDataArray[playerID].barracksAssemblyPoints[group].x; + int const assemblyY = DAT_GameState::instance.playerDataArray[playerID].barracksAssemblyPoints[group].y; + for (int i = offset; i < 49; ++i) { + int const x = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[i].x + assemblyX; + int const y = DAT_BuildingDefinedData::instance.SearchRelatedXYOffsets_1[i].y + assemblyY; + int const tile = DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x; + int const occupantID = DAT_TileMapState::instance.UnitLayer[tile]; + if (occupantID != 0 && occupantID != unitID + && DAT_UnitsState::instance.units[unitID].movementRelated == 8) { + continue; + } + if (MACRO_CALL_MEMBER( + Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + != 0) { + this->DAT_TempXOffset = x; + this->DAT_TempYOffset = y; + if (x == DAT_UnitsState::instance.units[unitID].x + && y == DAT_UnitsState::instance.units[unitID].y) { + return FALSE; + } + return TRUE; + } + } + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].barracks.id <= 0) { + return FALSE; + } + if (requestedGroup == 6) { + if (DAT_GameState::instance.playerDataArray[playerID].barracksAssemblyPoints[5].x != 0) { + offset = DAT_GameState::instance.playerDataArray[playerID].rallySearchOffset; + } + } else if (requestedGroup == 5) { + if (DAT_GameState::instance.playerDataArray[playerID].barracksAssemblyPoints[6].x != 0) { + offset -= DAT_GameState::instance.playerDataArray[playerID].rallySearchOffset; + } + } + for (int i = offset; i < 72; ++i) { + int const x + = DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[group][i].x; + int const y + = DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[group][i].y; + if ((uint)x > 399 || (uint)y > 399 + || DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[y * 400 + x] == 0) { + continue; + } + int const occupantID + = DAT_TileMapState::instance + .UnitLayer[DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x]; + if (occupantID != 0 && occupantID != unitID + && DAT_UnitsState::instance.units[unitID].movementRelated == 8) { + continue; + } + this->DAT_TempXOffset = x; + this->DAT_TempYOffset = y; + if (x == DAT_UnitsState::instance.units[unitID].x && y == DAT_UnitsState::instance.units[unitID].y) { + return FALSE; + } + return TRUE; + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/processBuildingIDsNeedPeasantsQueue.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/processBuildingIDsNeedPeasantsQueue.cpp new file mode 100644 index 000000000..d7ac898ef --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/processBuildingIDsNeedPeasantsQueue.cpp @@ -0,0 +1,139 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x0040F9D0 + void BuildingsState::processBuildingIDsNeedPeasantsQueue(undefined4 playerID) + { + // Assigns peasants to the free worker slots of the queued buildings + for (int i = 0; i < this->DAT_CountOfBuildingsNeedPeasants; ++i) { + int buildingID = this->DAT_BuildingIDsNeedPeasantsQueue[i]; + if (this->buildings[buildingID].buildingTypeBasedEmployeeCount == 1) { + UnitType workerType = (UnitType)DAT_BuildingDefinedData::instance + .WorkerTypeForBuildingType[this->buildings[buildingID].buildingType]; + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 0); + continue; + } + + if (this->buildings[buildingID].buildingType == BT_QUARRY) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 0) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(OpenSHC::Map::Units::UT_QUARRYMASON, buildingID, playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 0); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 1) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(OpenSHC::Map::Units::UT_QUARRYMASON, buildingID, playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 1); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 2) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(OpenSHC::Map::Units::UT_QUARRYMASON, buildingID, playerID, 2); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 2); + } + + } else if (this->buildings[buildingID].buildingType == BT_IRONMINE) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 0) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(OpenSHC::Map::Units::UT_MINER, buildingID, playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 0); + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 1) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(OpenSHC::Map::Units::UT_TRANSPORTMINER, buildingID, playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 1); + } + } else { + // The mill, water pot and cathedral share the code for their three workers + UnitType workerType; + if (this->buildings[buildingID].buildingType == BT_MILL) { + workerType = (UnitType)DAT_BuildingDefinedData::instance.WorkerTypeForBuildingType[BT_MILL]; + } else if (this->buildings[buildingID].buildingType == BT_WATERPOT) { + workerType = (UnitType)DAT_BuildingDefinedData::instance.WorkerTypeForBuildingType[BT_WATERPOT]; + } else if (this->buildings[buildingID].buildingType == BT_CHURCH) { + workerType = (UnitType)DAT_BuildingDefinedData::instance.WorkerTypeForBuildingType[BT_CHURCH]; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)( + buildingID, 0) + == FALSE) { + int unitID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, + this)(buildingID, unitID, 0); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)( + buildingID, 1) + == FALSE) { + int unitID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, + this)(buildingID, unitID, 1); + } + + continue; + } else if (this->buildings[buildingID].buildingType == BT_CATHEDRAL) { + workerType + = (UnitType)DAT_BuildingDefinedData::instance.WorkerTypeForBuildingType[BT_CATHEDRAL]; + } else { + continue; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 0) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 0); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 1) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 1); + } + + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::hasWorker, this)(buildingID, 2) + == FALSE) { + int unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::assignPeasantToBuilding, + DAT_UnitsState::ptr)(workerType, buildingID, playerID, 2); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::assignWorkerToBuilding, this)( + buildingID, unitID, 2); + } + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/processDamageToUnitsOnBuilding.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/processDamageToUnitsOnBuilding.cpp new file mode 100644 index 000000000..397ab0a79 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/processDamageToUnitsOnBuilding.cpp @@ -0,0 +1,52 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x004106D0 + void BuildingsState::processDamageToUnitsOnBuilding(int buildingID, int damagePercentage) + { + int i = 0; + int const size = this->buildings[buildingID].widthOrHeight; + int const x = this->buildings[buildingID].x; + int const y = this->buildings[buildingID].y; + do { + MACRO_CALL_MEMBER(TileMapState_Func::getBuildingSizeIndexMappingData, DAT_TileMapState::ptr)(i, size); + for (int unitID = DAT_TileMapState::instance + .UnitLayer[DAT_ViewportRenderState::instance + .translationMatrix[y + DAT_TileMapState::instance.buildingY] + .addXgetTile + + DAT_TileMapState::instance.buildingX + x]; + unitID != 0; unitID = DAT_UnitsState::instance.units[unitID].nextUnitOnTheSameTile) { + int const maxHealth = DAT_UnitsState::instance.units[unitID].maxHealth; + DAT_UnitsState::instance.units[unitID].health += maxHealth * damagePercentage / -100; + if (DAT_UnitsState::instance.units[unitID].health <= 0) { + DAT_UnitsState::instance.units[unitID].health = 0; + DAT_UnitsState::instance.units[unitID].dying = 1; + DAT_UnitsState::instance.units[unitID].animationCycleNumber = 0; + DAT_UnitsState::instance.units[unitID].state.generic = Units::States::US_STONE_DEATH_01; + } + int healthPercentage; + if (maxHealth == 0) { + healthPercentage = 100; + } else { + healthPercentage = DAT_UnitsState::instance.units[unitID].health * 100 / maxHealth; + } + DAT_UnitsState::instance.units[unitID].healthPercentage = healthPercentage; + DAT_UnitsState::instance.units[unitID].healthbar = (short)healthPercentage / 10; + } + ++i; + } while (i < DAT_TileMapState::instance.constructionTileCount); + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/processResourceLoss.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/processResourceLoss.cpp new file mode 100644 index 000000000..e6ca808c8 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/processResourceLoss.cpp @@ -0,0 +1,82 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0041BD70 + void BuildingsState::processResourceLoss(int playerID, ResourceType resourceType, int amount, int param_4) + { + int foundStorage = 0; + if (resourceType == 0) { + return; + } + if (DAT_GameCore::instance.gameMode_2 == Game::GM_SIEGE_THAT) { + if (param_4 == 0) { + DAT_GameState::instance.playerDataArray[playerID].startResources[resourceType] -= amount; + } + return; + } + BuildingType const storageType + = MACRO_CALL_MEMBER(BuildingsState_Func::getBuildingStorageTypeForResourceType, this)(resourceType); + if (storageType == BT_MANORHOUSE) { + if (param_4 == 0) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] -= amount; + } + return; + } + for (int buildingID = 1; buildingID < this->maxBuildingsCount; ++buildingID) { + if (this->buildings[buildingID].logicalState != BLS_NORMAL) { + continue; + } + if (this->buildings[buildingID].buildingType != storageType + || this->buildings[buildingID].owner != playerID + || this->buildings[buildingID].resources[resourceType] <= 0) { + continue; + } + if (param_4 == 0) { + this->buildings[buildingID].someResourceNumber = 0; + } + foundStorage = 1; + if (this->buildings[buildingID].resources[resourceType] >= amount) { + if (param_4 != 0) { + this->buildings[buildingID].someResourceNumber = amount; + } else { + this->buildings[buildingID].resources[resourceType] -= amount; + DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] -= amount; + } + amount = 0; + } else { + amount -= this->buildings[buildingID].resources[resourceType]; + if (param_4 != 0) { + this->buildings[buildingID].someResourceNumber + = this->buildings[buildingID].resources[resourceType]; + } else { + int const left = this->buildings[buildingID].resources[resourceType]; + this->buildings[buildingID].resources[resourceType] = 0; + DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] -= left; + } + } + if (param_4 == 0) { + MACRO_CALL_MEMBER(BuildingsState_Func::computeResourceSumForBuilding, this)(buildingID); + MACRO_CALL_MEMBER(BuildingsState_Func::countPlayerResources, this)(playerID); + } + MACRO_CALL_MEMBER(TileMapState_Func::updateBuildingGraphicsLayer, DAT_TileMapState::ptr)(buildingID); + } + if (foundStorage == 0) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] = 0; + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/setNewOnFarmDestination.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/setNewOnFarmDestination.cpp new file mode 100644 index 000000000..fbaf01040 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/setNewOnFarmDestination.cpp @@ -0,0 +1,96 @@ +#include "../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_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +#include + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040EA00 + BOOLEnum BuildingsState::setNewOnFarmDestination(int buildingID) + { + uint const entryX = this->buildings[buildingID].buildingEntryX; + uint const entryY = this->buildings[buildingID].buildingEntryY; + bool const onMap = entryX <= 399 && entryY <= 399 + && DAT_ViewportRenderState::instance.DAT_BinaryTileMap400x400[entryY * 400 + entryX] != 0; + if (!onMap) { + return FALSE; + } + int const entryArea + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_ViewportRenderState::instance.translationMatrix[entryY].addXgetTile + + entryX]; + // The header has no field for the short at 0x26e. + int direction = this->buildings[buildingID].someFarmRelatedState == 0x51 ? 4 : 2; + for (int i = 0; i < 24; ++i) { + int const tile = this->buildings[buildingID].tileRefs[i]; + int const row = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int const damage = (char)DAT_TileMapState::instance.DamageLayer[tile]; + DAT_BuildingsState::instance.farmerDestinationTile = tile; + int const height + = MACRO_CALL_MEMBER(TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)(tile); + if (this->buildings[buildingID].farmGrowState == 5) { + if (damage < 14 || damage > 27) { + continue; + } + for (int k = 0; k < 4; ++k) { + int const target = DAT_TileMapState::instance.directionTranslationMatrix[row][direction] + tile; + DAT_BuildingsState::instance.hopFarmerDestinationOffsetX + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction] + .int_.xOffset; + DAT_BuildingsState::instance.hopFarmerDestinationOffsetY + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction] + .int_.yOffset; + if ((short)DAT_TileMapState::instance.PathConnectionLayer[target] == entryArea + && abs((int)MACRO_CALL_MEMBER( + TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)(target) + - height) + < 16) { + return TRUE; + } + direction += 2; + if (direction >= 8) { + direction = 0; + } + } + } else if (this->buildings[buildingID].farmGrowState == 3) { + if (damage < 0 || damage > 1) { + continue; + } + for (int k = 0; k < 4; ++k) { + int const target = DAT_TileMapState::instance.directionTranslationMatrix[row][direction] + tile; + DAT_BuildingsState::instance.hopFarmerDestinationOffsetX + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction] + .int_.xOffset; + DAT_BuildingsState::instance.hopFarmerDestinationOffsetY + = DAT_TerrainDefinedData::instance.clockwiseCardinalTranslationMatrix[direction] + .int_.yOffset; + if ((short)DAT_TileMapState::instance.PathConnectionLayer[target] == entryArea + && abs((int)MACRO_CALL_MEMBER( + TileMapState_Func::getTotalHeightAtTile, DAT_TileMapState::ptr)(target) + - height) + < 16) { + return TRUE; + } + direction += 2; + if (direction >= 8) { + direction = 0; + } + } + } else { + return FALSE; + } + } + return FALSE; + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/setupBarracksCampgroundPositions.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/setupBarracksCampgroundPositions.cpp new file mode 100644 index 000000000..ac179d7d5 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/setupBarracksCampgroundPositions.cpp @@ -0,0 +1,119 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040D120 + void BuildingsState::setupBarracksCampgroundPositions(int playerID) + { + int paradeGround1 = 0; + int paradeGround2 = 0; + int paradeGround3 = 0; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations), 0, + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations); + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocationsTotal = 0; + if (DAT_GameState::instance.playerDataArray[playerID].barracks.id <= 0) { + return; + } + int buildingID; + for (buildingID = 1; buildingID < this->maxBuildingsCount; ++buildingID) { + if (this->buildings[buildingID].logicalState == 0 + || this->buildings[buildingID].logicalState == BLS_REMOVE + || this->buildings[buildingID].owner != playerID) { + continue; + } + if (this->buildings[buildingID].buildingType != BT_PARADEGROUND2 + && this->buildings[buildingID].buildingType != BT_PARADEGROUND3 + && this->buildings[buildingID].buildingType != BT_PARADEGROUND4) { + continue; + } + // quarryStockpileID holds the linked building here. + if (DAT_BuildingsState::instance + .buildings[DAT_BuildingsState::instance.buildings[buildingID].quarryStockpileID] + .buildingType + != BT_BARRACKS) { + continue; + } + if (this->buildings[buildingID].buildingType == BT_PARADEGROUND2) { + paradeGround1 = buildingID; + } else if (this->buildings[buildingID].buildingType == BT_PARADEGROUND3) { + paradeGround2 = buildingID; + } else if (this->buildings[buildingID].buildingType == BT_PARADEGROUND4) { + paradeGround3 = buildingID; + } + } + if (paradeGround1 == 0 || paradeGround2 == 0 || paradeGround3 == 0) { + return; + } + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocationsTotal = 72; + for (int formation = 0; formation < 6; ++formation) { + int const shape = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_1[formation]; + // The loop index above is reused, so an unknown selector keeps the previous building. + int const selector0 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][0]; + if (selector0 == 0) { + buildingID = paradeGround1; + } else if (selector0 == 1) { + buildingID = paradeGround2; + } else if (selector0 == 2) { + buildingID = paradeGround3; + } + int const x0 = this->buildings[buildingID].x; + int const y0 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][i].x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x0; + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][i].y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y0; + } + int const selector1 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][1]; + if (selector1 == 0) { + buildingID = paradeGround1; + } else if (selector1 == 1) { + buildingID = paradeGround2; + } else if (selector1 == 2) { + buildingID = paradeGround3; + } + int const x1 = this->buildings[buildingID].x; + int const y1 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][24 + i].x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x1; + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][24 + i].y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y1; + } + int const selector2 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][2]; + if (selector2 == 0) { + buildingID = paradeGround1; + } else if (selector2 == 1) { + buildingID = paradeGround2; + } else if (selector2 == 2) { + buildingID = paradeGround3; + } + int const x2 = this->buildings[buildingID].x; + int const y2 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][48 + i].x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x2; + DAT_GameState::instance.playerDataArray[playerID].barracksParadegroundLocations[formation][48 + i].y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y2; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/setupMercenaryPostCampgroundPositions.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/setupMercenaryPostCampgroundPositions.cpp new file mode 100644 index 000000000..c09a8f69a --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/setupMercenaryPostCampgroundPositions.cpp @@ -0,0 +1,131 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040D400 + void BuildingsState::setupMercenaryPostCampgroundPositions(int playerID) + { + int paradeGround1 = 0; + int paradeGround2 = 0; + int paradeGround3 = 0; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(DAT_GameState::instance.playerDataArray[playerID].structure), 0, + &DAT_GameState::instance.playerDataArray[playerID].structure); + DAT_GameState::instance.playerDataArray[playerID].structureRelated1 = 0; + if (DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id <= 0) { + return; + } + int buildingID; + for (buildingID = 1; buildingID < this->maxBuildingsCount; ++buildingID) { + if (this->buildings[buildingID].logicalState == 0 + || this->buildings[buildingID].logicalState == BLS_REMOVE + || this->buildings[buildingID].owner != playerID) { + continue; + } + if (this->buildings[buildingID].buildingType != BT_PARADEGROUND2 + && this->buildings[buildingID].buildingType != BT_PARADEGROUND3 + && this->buildings[buildingID].buildingType != BT_PARADEGROUND4) { + continue; + } + // quarryStockpileID holds the linked building here. + if (DAT_BuildingsState::instance + .buildings[DAT_BuildingsState::instance.buildings[buildingID].quarryStockpileID] + .buildingType + != BT_MERCENARYPOST) { + continue; + } + if (this->buildings[buildingID].buildingType == BT_PARADEGROUND2) { + paradeGround1 = buildingID; + } else if (this->buildings[buildingID].buildingType == BT_PARADEGROUND3) { + paradeGround2 = buildingID; + } else if (this->buildings[buildingID].buildingType == BT_PARADEGROUND4) { + paradeGround3 = buildingID; + } + } + if (paradeGround1 == 0 || paradeGround2 == 0 || paradeGround3 == 0) { + return; + } + DAT_GameState::instance.playerDataArray[playerID].structureRelated1 = 72; + for (int formation = 0; formation < 6; ++formation) { + int const shape = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_1[formation]; + // The loop index above is reused, so an unknown selector keeps the previous building. + int const selector0 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][0]; + if (selector0 == 0) { + buildingID = paradeGround1; + } else if (selector0 == 1) { + buildingID = paradeGround2; + } else if (selector0 == 2) { + buildingID = paradeGround3; + } + int const x0 = this->buildings[buildingID].x; + int const y0 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][0][i] + .x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x0; + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][0][i] + .y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y0; + } + int const selector1 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][1]; + if (selector1 == 0) { + buildingID = paradeGround1; + } else if (selector1 == 1) { + buildingID = paradeGround2; + } else if (selector1 == 2) { + buildingID = paradeGround3; + } + int const x1 = this->buildings[buildingID].x; + int const y1 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][1][i] + .x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x1; + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][1][i] + .y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y1; + } + int const selector2 + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_2[formation][2]; + if (selector2 == 0) { + buildingID = paradeGround1; + } else if (selector2 == 1) { + buildingID = paradeGround2; + } else if (selector2 == 2) { + buildingID = paradeGround3; + } + int const x2 = this->buildings[buildingID].x; + int const y2 = this->buildings[buildingID].y; + for (int i = 0; i < 24; ++i) { + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][2][i] + .x + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].x + x2; + DAT_GameState::instance.playerDataArray[playerID] + .structure.mercenaryOutpostCampgroundLocations[formation][2][i] + .y + = DAT_BuildingDefinedData::instance.PlayerDataUnknownStructureRelatedArray_3[shape][i].y + y2; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/spawnRandomFireEffectOnBuilding.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/spawnRandomFireEffectOnBuilding.cpp new file mode 100644 index 000000000..55f96e15b --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/spawnRandomFireEffectOnBuilding.cpp @@ -0,0 +1,64 @@ +#include "../BuildingsState.func.hpp" + +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Map/Entities/EntityState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/DE/SHCDE/eSFX.hpp" +#include "OpenSHC/Map/Entities/EntityType.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x00410800 + void BuildingsState::spawnRandomFireEffectOnBuilding(int buildingID, undefined4 playerID) + { + if (this->buildings[buildingID].fireDuration < 400) { + return; + } + int const size = this->buildings[buildingID].widthOrHeight; + if (size <= 3) { + if ((this->buildings[buildingID].fireRelatedRNG1 + this->buildings[buildingID].fireDuration) + % (24 - size * 5) + != 0) { + return; + } + } else if (size <= 6) { + if ((this->buildings[buildingID].fireRelatedRNG1 + this->buildings[buildingID].fireDuration) + % ((8 - size) * 5) + != 0) { + return; + } + } else { + if ((this->buildings[buildingID].fireRelatedRNG1 + this->buildings[buildingID].fireDuration) + % ((16 - size) * 5) + != 0) { + return; + } + } + int const height + = DAT_TileMapState::instance.HeightLayer[this->buildings[buildingID].currentTilePositionAdjusted]; + int const x = (SEC_RNG::instance.currentNumber2 % (int)this->buildings[buildingID].widthOrHeight + + this->buildings[buildingID].x) + * 8; + int const y = ((SEC_RNG::instance.currentNumber2 >> 8) % (int)this->buildings[buildingID].widthOrHeight + + this->buildings[buildingID].y) + * 8; + // EntityType has no constant for 32. + MACRO_CALL_MEMBER(Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)( + 5, playerID, 0, x, y, height, x, y, height, (Entities::EntityType)32, 0); + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + if ((SEC_RNG::instance.currentNumber1 & 1) != 0) { + MACRO_CALL_MEMBER(Audio::SFX::SFXState_Func::playSFXAtLocation, DAT_SFXState::ptr)( + x / 8, y / 8, DE::SHCDE::FX_FIRE_POP); + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Buildings/BuildingsState/updateBuildingAreaTileGraphics.cpp b/src/OpenSHC/Map/Buildings/BuildingsState/updateBuildingAreaTileGraphics.cpp new file mode 100644 index 000000000..7485f4ad3 --- /dev/null +++ b/src/OpenSHC/Map/Buildings/BuildingsState/updateBuildingAreaTileGraphics.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/GMTotalPicturesProcessed.hpp" + +namespace OpenSHC { +namespace Map { + namespace Buildings { + + // FUNCTION: STRONGHOLDCRUSADER 0x0040EFD0 + void BuildingsState::updateBuildingAreaTileGraphics(int param_1) + { + for (int i = 0; i < 23; ++i) { + int tile = this->buildings[param_1].tileRefs[4 + i]; + int const damage = (char)DAT_TileMapState::instance.DamageLayer[tile]; + int const stage + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::getRubbleGraphicStageForDamageLevel, + DAT_TileMapState::ptr)(damage); + int gfx = GMTotalPicturesProcessed::instance[14] + 55 + stage; + if (gfx != DAT_TileMapState::instance.GfxLayer[tile]) { + DAT_TileMapState::instance.GfxLayer[tile] = gfx; + DAT_TileMapState::instance.MiscDisplayLayer[tile] &= 0xfff3; + } + } + } + + } +} +} diff --git a/src/OpenSHC/Map/Version/UpgradeBuildingField4.cpp b/src/OpenSHC/Map/Version/UpgradeBuildingField4.cpp index dc56f4c40..f4f7a26eb 100644 --- a/src/OpenSHC/Map/Version/UpgradeBuildingField4.cpp +++ b/src/OpenSHC/Map/Version/UpgradeBuildingField4.cpp @@ -15,7 +15,7 @@ namespace Map { { for (int buildingID = 1; buildingID < 2000; ++buildingID) { if (DAT_BuildingsState::instance.buildings[buildingID].logicalState != (BuildingLogicalState)0) { - DAT_BuildingsState::instance.buildings[buildingID].field201_0x2c6 = 0; + DAT_BuildingsState::instance.buildings[buildingID].field200_0x2c6 = 0; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7f65823de..c0e612a7e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -4345,7 +4345,7 @@ SHC_3BB0A8C1_0x0040C1A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040C1F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0040C300 | 0.0% | Pending +SHC_3BB0A8C1_0x0040C300 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040C4B0 | 100.0% | Reimplemented @@ -4763,7 +4763,7 @@ SHC_3BB0A8C1_0x0040C7F7 | 0.0% | Pending SHC_3BB0A8C1_0x0040C7F8 | 0.0% | Pending -SHC_3BB0A8C1_0x0040C800 | 0.0% | Pending +SHC_3BB0A8C1_0x0040C800 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040C918 | 0.0% | Pending @@ -4961,21 +4961,21 @@ SHC_3BB0A8C1_0x0040CB90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040CBB0 | 0.0% | Pending -SHC_3BB0A8C1_0x0040CC30 | 0.0% | Pending +SHC_3BB0A8C1_0x0040CC30 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040CF20 | 0.0% | Pending SHC_3BB0A8C1_0x0040D090 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0040D120 | 0.0% | Pending +SHC_3BB0A8C1_0x0040D120 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040D190 | 0.0% | Pending -SHC_3BB0A8C1_0x0040D400 | 0.0% | Pending +SHC_3BB0A8C1_0x0040D400 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040D470 | 0.0% | Pending -SHC_3BB0A8C1_0x0040D6E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0040D6E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040D910 | 0.0% | Pending @@ -4985,7 +4985,7 @@ SHC_3BB0A8C1_0x0040DC70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040E040 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0040E120 | 0.0% | Pending +SHC_3BB0A8C1_0x0040E120 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040E330 | 100.0% | Reimplemented @@ -4993,7 +4993,7 @@ SHC_3BB0A8C1_0x0040E410 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040E550 | 0.0% | Pending -SHC_3BB0A8C1_0x0040E610 | 0.0% | Pending +SHC_3BB0A8C1_0x0040E610 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040E660 | 0.0% | Pending @@ -5005,7 +5005,7 @@ SHC_3BB0A8C1_0x0040E900 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040E990 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0040EA00 | 0.0% | Pending +SHC_3BB0A8C1_0x0040EA00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040EBF0 | 100.0% | Reimplemented @@ -5017,7 +5017,7 @@ SHC_3BB0A8C1_0x0040EE30 | 0.0% | Pending SHC_3BB0A8C1_0x0040EF40 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0040EFD0 | 0.0% | Pending +SHC_3BB0A8C1_0x0040EFD0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040F040 | 100.0% | Reimplemented @@ -5057,7 +5057,7 @@ SHC_3BB0A8C1_0x0040F790 | 0.0% | Pending SHC_3BB0A8C1_0x0040F8A0 | 0.0% | Pending -SHC_3BB0A8C1_0x0040F9D0 | 0.0% | Pending +SHC_3BB0A8C1_0x0040F9D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0040FC40 | 100.0% | Reimplemented @@ -5139,13 +5139,13 @@ SHC_3BB0A8C1_0x00410290 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00410320 | 0.0% | Pending -SHC_3BB0A8C1_0x00410440 | 0.0% | Pending +SHC_3BB0A8C1_0x00410440 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004105F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004105F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004106D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004106D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00410800 | 0.0% | Pending +SHC_3BB0A8C1_0x00410800 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00410920 | 100.0% | Reimplemented @@ -5371,9 +5371,9 @@ SHC_3BB0A8C1_0x004109E1 | 0.0% | Pending SHC_3BB0A8C1_0x004109E2 | 0.0% | Pending -SHC_3BB0A8C1_0x004109F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004109F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00410B10 | 0.0% | Pending +SHC_3BB0A8C1_0x00410B10 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00410C40 | 100.0% | Reimplemented @@ -6109,7 +6109,7 @@ SHC_3BB0A8C1_0x0041BC10 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0041BCA0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0041BD70 | 0.0% | Pending +SHC_3BB0A8C1_0x0041BD70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0041BE30 | 0.0% | Pending